这次比赛,看到了自己跟大家的差距,所谓的大神是从一点一滴练起的。不是说钻研得多高深,就多牛;而是所有的题干细节处理到位,所有能做的题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; }
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; }
#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; }
又有一个巨巨提供的代码,觉得挺好的,供大家学习string的细节处理:
#include <cstdio> #include <cstring> int main() { int N;scanf("%d",&N); while(N--) { int n,cnt=0; char s[16]; scanf("%d",&n); while(n) { int m=n%26; if(!m)m=26; s[cnt++]=m+64; n=(n-m)/26; } for(int i=cnt;i;--i) putchar(s[i-1]); puts(""); } return 0; }
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; }
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,有错误就不够完美,赛后题解只是补充学习,更多的是大家平时的细节注意,大家为着梦想加油!