GDUT预赛题解
这次比赛,看到了自己跟大家的差距,所谓的大神是从一点一滴练起的。不是说钻研得多高深,就多牛;而是所有的题干细节处理到位,所有能做的题1A,向bin神学习吧,同志们!一起加油!
说明:这个题解,有我自己的代码,也有bin神的,axp巨巨的,Tonny巨巨,还有好多帮助过我的人,希望群巨多多参与题解的建设,方便自己做总结,也方便群巨学习。
话不多说。从每一题开始(题意全部略去)。忘记了的请去这:请点我去看题
第一天
A.模拟。对3种情况,分别进行处理。容易出现的错误有:注意当队伍中已经没人的时候请忽略第2种事件,每组数据新开始的时候队伍中人数都为0!另外,我一开始实现的代码是用queue写的,不知道为什么超时了。。。估计是迭代器比较慢。AC代码如下:
#include <iostream> #include <algorithm> #include <stdio.h> #include <math.h> #include <map> #include <set> #include <vector> #include <string> #include <cstring> #include <sstream> #include <queue> #include <stack> using namespace std; #define input freopen("input.txt","r",stdin) #define output freopen("output.txt","w",stdout) #define For1(i,a,b) for (i=a;i<b;i++) #define For2(i,a,b) for (i=a;i<=b;i++) #define Fill(x,a) memset(x,a,sizeof(x)) #define inf 99999999 #define pi 3.1415926535897932384626433832795028841971 typedef long long LL; const int maxn=10000050; int head,tail; int num[maxn]; int main(){ //freopen("input.txt","r",stdin); int t,n,a,b,k; scanf("%d",&t); while(t--){ scanf("%d",&n); memset(num,0,sizeof(num)); head=0,tail=0; while(n--){ scanf("%d",&a); if (a==1){ scanf("%d",&b); num[tail]=b; tail++; } else if (a==2){ if (head<tail) head++; } else{ scanf("%d",&k); if (head+k<=tail) printf("%d\n",num[head+k-1]); else puts("na li you zhe me duo ren"); } } } return 0; }
细节:注意head<tail这句,是处理重点语句的。我当时写了等号,意味着没有处理一开始就是选项2的情况,题意中说明了是有这种可能的。
B.按照题意,对输入的数字进行转换。我的代码很挫,改了又改最后对的。对于n=1000的这种小数据,告诉大家一个1A的方法,用freopen形成一个1到1000的测试数据,看看答案是不是有规律连续的即可。
我的代码:
#include <iostream> #include <algorithm> #include <stdio.h> #include <math.h> #include <map> #include <set> #include <vector> #include <string> #include <cstring> #include <sstream> #include <queue> #include <stack> using namespace std; #define input freopen("input.txt","r",stdin) #define output freopen("output.txt","w",stdout) #define For1(i,a,b) for (i=a;i<b;i++) #define For2(i,a,b) for (i=a;i<=b;i++) #define Fill(x,a) memset(x,a,sizeof(x)) #define inf 99999999 #define pi 3.1415926535897932384626433832795028841971 void Print(int n){ int i,j,k; if (n<=26){ printf("%c\n",n+'A'-1); return; } if (n>=27&&n<=26*27){ for(j=1;j<=26;j++) for(k=1;k<=26;k++){ if (j*26+k==n){ printf("%c",j+'A'-1); printf("%c",k+'A'-1); puts(""); return; } } } printf("A"); for(j=1;j<=26;j++) for(k=1;k<=26;k++){ if (j*26+k==n-26*26){ printf("%c",j+'A'-1); printf("%c",k+'A'-1); puts(""); return; } } } int main(){ int t; int n; int ans[500]; scanf("%d",&t); while(t--){ scanf("%d",&n); Print(n); } return 0; }
上上bin神的代码,每道题都可以学学不同的思路,有时候有了题解,不要懒,自己实现实现
#include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> #include <vector> #include <queue> #include <set> #include <map> #include <string> #include <math.h> #include <stdlib.h> #include <time.h> using namespace std; int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); int T; int n; scanf("%d",&T); while(T--){ scanf("%d",&n); if(n <= 26){ printf("%c\n",(char)('A'+n-1)); } else if(n <= 26+26*26){ n -= 27; printf("%c%c\n",(char)('A'+n/26),(char)('A'+n%26)); } else { n -= 26+26*26+1; printf("%c%c%c\n",(char)('A'+n/26/26),(char)('A'+(n/26)%26),(char)('A'+n%26)); } } return 0; }
C.这道题不需要题解的吧。。给大家提供个bin神快的诀窍。
sort(a,a+n)代表对a数组中的a[0]到a[n]从小到大排序
reverse(a,a+n)代表对a数组中所有元素反序存储。之后的。大家懂
D.这个题是比较好的一道题。有多种做法。
先说说思路。
1.bin神思路。dp[i][0]代表共i位数字,最后1位为0的不含有11的数目,dp[i][1]代表共i位数字,最后1位为1的不含有11的数目,这样,答案就是2^n-dp[i][0]-dp[i][1]。递推过程很好想。代码如下:
#include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> #include <vector> #include <queue> #include <set> #include <map> #include <string> #include <math.h> #include <stdlib.h> #include <time.h> using namespace std; const int MOD = 1e9+7; int dp[1000010][2]; void Add(int &a,int b){ a += b; if(a >= MOD) a -= MOD; } int two[1000010]; int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); memset(dp,0,sizeof(dp)); dp[1][0] = dp[1][1] = 1; two[1] = 2; for(int i = 2;i <= 1000000;i++){ dp[i][0] = dp[i-1][1]+dp[i-1][0]; if(dp[i][0] >= MOD) dp[i][0] -= MOD; dp[i][1] = dp[i-1][0]; two[i] = 2LL*two[i-1]%MOD; } int T; int n; cin>>T; while(T--){ scanf("%d",&n); int ans = two[n]-(dp[n][0]+dp[n][1])%MOD; ans = (ans%MOD+MOD)%MOD; printf("%d\n",ans); } return 0; }
2.dfs处理所有小数据(或者手算打表)。发现ans[n]=2*ans[n-1]-f[n-1],其中f代表斐波那契数列,其中f[1]=f[2]=1。打表不贴代码,大家自己实现吧。
3.axp巨巨提供:光棍是递推,长度为n的有两种情况,110+长度为n-3不符合情况的,0或1加上长度为n-1符合要求的
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <queue> #include <set> #include <map> #include <string> #include <cmath> #include <cstdlib> #include <ctime> using namespace std; const int maxn = 1000100; const int mod = 1000000007; int arr[maxn]; int two[maxn]; int T,n; int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); two[0]=1; for(int i=1;i<maxn;i++) two[i]=(two[i-1]*2)%mod; arr[2]=1; for(int i=3;i<maxn;i++) { arr[i]=( (2*arr[i-1])%mod + two[i-3]-arr[i-3] )%mod; while(arr[i]<0) arr[i]+=mod; } cin>>T; while(T--) { scanf("%d",&n); printf("%d\n",arr[n]); } return 0; }
5.物理题。。大家注意,题中条件少,意味着需要自己找。判断要求为:炮弹45度出发打不中的话就肯定打不中了(高中物理)。就是求以v斜向上45度发射,求最大距离x与d的关系。x=v^2/g。分解成水平速度v0和垂直速度vy。大家都会的。细心就好
6.我大概懂了,axp巨巨教的。每次循环都改动字符串,就是第i位和第len-k+i相同所以就统计所有相隔len-k的字符,选出出现次数最多的,把这些字符都修改为这个字符,统计要修改的次数就是答案了。代码如下:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <queue> #include <set> #include <map> #include <string> #include <cmath> #include <cstdlib> #include <ctime> using namespace std; int ans; const int maxn = 1100; char ch[maxn]; int T,k; int arr[26]; int be; int l; int f(int x) { memset(arr,0,sizeof(arr)); int re=0; int r=0; while(x<l) { r++; arr[ch[x]-'A']++; x=be+x; } for(int i=0;i<26;i++) re=max(re,arr[i]); return r-re; } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); cin>>T; while(T--) { scanf("%s%d",ch,&k); l=strlen(ch); be=l-k; ans=0; for(int i=0;i<k && i<l-k;i++) { ans+=f(i); } printf("%d\n",ans); } return 0; }
上面这题我一直没过是因为我用贪心思考的,判断的时候没有管到连续的修改值的问题。axp巨巨Hack我的数据是aaabbbccc 8。我的贪心代码比较渣,只关注了第i位和第i位匹配位和第len-i位的匹配位。没有想到链接的关系。Hack数据len=9,k=8,意思是连续的都相同,即为所有字符都一样。所以,贪心策略不知道实行多少次,没有贪心的正确性保证,只能用类似搜索的方法实现。
7.既然是颗树,既然是n=1000,dfs和bfs是不会有问题的。我的思路,用ans[i]记录,若等于0说明未访问过,若等于j说明走到i之前必须过j(由于是颗树),dfs时数目肯定不会大,因为每次扩展的节点是有限的。代码如下:
#include <iostream> #include <algorithm> #include <stdio.h> #include <math.h> #include <map> #include <set> #include <vector> #include <string> #include <cstring> #include <sstream> #include <queue> #include <stack> using namespace std; #define input freopen("input.txt","r",stdin) #define output freopen("output.txt","w",stdout) #define For1(i,a,b) for (i=a;i<b;i++) #define For2(i,a,b) for (i=a;i<=b;i++) #define Fill(x,a) memset(x,a,sizeof(x)) #define inf 99999999 #define pi 3.1415926535897932384626433832795028841971 const int maxn=2000; int t,n,s; int mp[maxn][maxn]; int ans[maxn]; void dfs(int start){ int i,j; for(i=1;i<=n;i++) if (!ans[i]&&mp[start][i]){ ans[i]=start; dfs(i); } } int main(){ //freopen("input.txt","r",stdin); scanf("%d",&t); int a,b; int i,j,k; while(t--){ memset(mp,0,sizeof(mp)); memset(ans,0,sizeof(ans)); scanf("%d%d",&n,&s); ans[s]=-1; for(i=1;i<n;i++){ scanf("%d%d",&a,&b); mp[a][b]=mp[b][a]=1; } dfs(s); for(i=1;i<=n;i++) printf("%d%c",ans[i],i==n?'\n':' '); } return 0; }
8.大大的水题。给个式子就好了。
num[1]=1; num[2]=2; for(i=3;i<=1000;i++) num[i]=num[i-1]+i-1;
小数据打表就好。
初赛的题解就到这里。谢谢bin神,axp巨巨,Tonny巨巨和群巨的帮助和支持。希望大家也能分享自己的AC和各种错误,一起提高。
Hint:比赛就是这样,还记得我初中数学老师说的,打不了满分就不要说题目简单。放到ACM也一样,这道题你不是1A就没有资格说它简单,这场比赛没有AK,有错误就不够完美,赛后题解只是补充学习,更多的是大家平时的细节注意,大家为着梦想加油!
附个我的正能量:
大家觉得刷题烦了看看我的人生正能量