训练赛题解
突然想到好久以前做完这份题目没写题解。蛮来写写吧。很多细节已经忘记了。。
第一题
很简单的字符串比对是否b包含a。不包含就报NO,包含就YES。。坑爹的第一次!!。把strlen放在了for循环里面。。就超时了。。超时了。。
注意:for里面的条件每次也会重新计算。
Description
Given two strings s and t, you have to decide whether s is a subsequence of t, i.e. if you can remove characters from t such that the concatenation of the remaining characters is s.
Input
Output
Sample Input
sequence subsequence person compression VERDI vivaVittorioEmanueleReDiItalia caseDoesMatter CaseDoesMatter
Sample Output
Yes No Yes No
下附代码
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 #include<cmath> 5 #define INF 1000000 6 char s[100005],t[100005]; 7 int main() 8 { 9 int i=0,j=0,s_len,t_len; 10 while(scanf("%s%s",s,t)!=EOF) 11 { 12 i=0;j=0; 13 s_len=strlen(s); 14 t_len=strlen(t); 15 for(i;i<s_len&&j<t_len;) 16 if(s[i]==t[j]) 17 {i++;j++;} 18 else 19 j++; 20 if(i==strlen(s)) 21 printf("Yes\n"); 22 else 23 printf("No\n"); 24 } 25 return 0; 26 }
第二题
找规律。。其实也可以还原。但是找到规律的话也是可以做的。就是写代码的时候要认真点。思路是相邻做差,得到一个新的数组,新数组有数字,说明肯定有差括号,是1,然后这个新数组如果有一串0,说明原来的数字都是相等的,则第一位0肯定是1,但是接下来的0,就要继续往前找对应的括号,然后增加数字,具体的已经忘记了。但是就是找规律。这题1A。
Description
q By an integer sequence P = p1 p2...pn where pi is the number of left parentheses before the ith right parenthesis in S (P-sequence).
q By an integer sequence W = w1 w2...wn where for each right parenthesis, say a in S, we associate an integer which is the number of right parentheses counting from the matched left parenthesis of a up to a. (W-sequence).
Following is an example of the above encodings:
S (((()()())))
P-sequence 4 5 6666
W-sequence 1 1 1456
Write a program to convert P-sequence of a well-formed string to the W-sequence of the same string.
Input
Output
Sample Input
2 6 4 5 6 6 6 6 9 4 6 6 6 6 8 9 9 9
Sample Output
1 1 1 4 5 6 1 1 2 4 5 1 1 3 9
下附代码:
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 #include<cmath> 5 #include<algorithm> 6 #include<queue> 7 #define INF 1000005 8 using namespace std; 9 queue<int>q; 10 int s[1000005]={0},mark[1000005]; 11 int main() 12 { 13 int n,first,late,i,m,ans,t; 14 scanf("%d",&n); 15 while(n--) 16 { 17 for(i=0;i<30;i++) 18 {s[i]=0;mark[i]=0;} 19 scanf("%d",&m); 20 first=0; 21 for(i=0;i<m;i++) 22 { 23 scanf("%d",&late); 24 s[i]=late-first; 25 first=late; 26 } 27 for(i=0;i<m;i++) 28 { 29 if(s[i]) 30 { 31 if(i!=m-1) 32 printf("1 "); 33 else 34 printf("1\n"); 35 } 36 else 37 { 38 t=i;ans=0; 39 while(!s[t]||mark[t]==s[t]) 40 { 41 ans+=mark[t]; 42 t--; 43 } 44 while(mark[t]+1==s[t]) 45 { 46 mark[t]++; 47 ans+=s[t]; 48 t--; 49 while(!s[t]||mark[t]==s[t]) 50 { 51 ans+=mark[t]; 52 t--; 53 } 54 } 55 mark[t]++; 56 if(i!=m-1) 57 printf("%d ",ans+mark[t]+1); 58 else 59 printf("%d\n",ans+mark[t]+1); 60 } 61 } 62 } 63 return 0; 64 }
第三题
一个二叉树的前序中序序列,还原后序序列,用到了递归分治的思想,主要要分清楚两个序列的头和尾在哪里,然后可以通过找根找到中序序列中间的根,从而继续分开这两个序列。关键代码是下面这个
if(k-cc)
turn(aa+1,k-cc+aa,cc,k-1);
if(dd-k)
turn(aa+k-cc+1,bb,k+1,dd);
错了两次,算是一道考细节的递归。
下附代码:
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 #include<cmath> 5 #include<algorithm> 6 #include<queue> 7 #define INF 1000000 8 using namespace std; 9 char a[50],b[50],c[50]; 10 void turn(int aa,int bb,int cc,int dd)//n是前序m是中序 11 { 12 int k=0; 13 while(a[aa]!=b[k]) 14 { 15 k++; 16 }//找根 17 if(k-cc) 18 turn(aa+1,k-cc+aa,cc,k-1); 19 if(dd-k) 20 turn(aa+k-cc+1,bb,k+1,dd); 21 printf("%c",a[aa]); 22 } 23 int main() 24 { 25 int i,m,n,ans,t,bg,j,num,k,h=0,sum=0; 26 while(scanf("%s%s",a,b)!=EOF) 27 { 28 t=strlen(a); 29 turn(0,t-1,0,t-1); 30 for(i=1;i<=t;i++) 31 printf("%c",c[i]); 32 printf("\n"); 33 } 34 return 0; 35 }
第四题:
BFS就行。用队列来存,注意一下具体细节。
Description
Farmer John has been informed of the location of a fugitive cow and wants to catch her immediately. He starts at a point N (0 ≤ N ≤ 100,000) on a number line and the cow is at a point K (0 ≤ K ≤ 100,000) on the same number line. Farmer John has two modes of transportation: walking and teleporting.
* Walking: FJ can move from any point X to the points X - 1 or X + 1 in a single minute
* Teleporting: FJ can move from any point X to the point 2 × X in a single minute.
If the cow, unaware of its pursuit, does not move at all, how long does it take for Farmer John to retrieve it?
Input
Output
Sample Input
5 17
Sample Output
4
Hint
下附代码:
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 #include<cmath> 5 #include<algorithm> 6 #include<queue> 7 #define INF 1000000 8 using namespace std; 9 queue<int>q; 10 int vis[1000005]={0}; 11 int main() 12 { 13 int a,b,cot,ans,t,mark=0,noww; 14 scanf("%d%d",&a,&b); 15 if(a==b) 16 printf("0\n"); 17 else 18 { 19 if(a+1==b||a-1==b||a*2==b) 20 printf("1\n"); 21 else 22 { 23 q.push(a); 24 vis[a]=1; 25 while(!q.empty()) 26 { 27 ans=q.front(); 28 q.pop(); 29 if(ans-1>=0) 30 { 31 noww=ans-1; 32 if(!vis[noww]) 33 {vis[noww]=vis[ans]+1;q.push(noww);} 34 if(noww==b) 35 {printf("%d\n",vis[noww]-1);break;} 36 } 37 if(ans+1<INF) 38 { 39 noww=ans+1; 40 if(!vis[noww]) 41 {vis[noww]=vis[ans]+1;q.push(noww);} 42 if(noww==b) 43 {printf("%d\n",vis[noww]-1);break;} 44 } 45 if(ans*2<INF) 46 { 47 noww=ans*2; 48 if(!vis[noww]) 49 {vis[noww]=vis[ans]+1;q.push(noww);} 50 if(noww==b) 51 {printf("%d\n",vis[noww]-1);break;} 52 } 53 } 54 } 55 } 56 return 0; 57 }
第五题:
一道判断是不是连通的,用并查集就可以判断,但是要做一点小处理,存储的时候如果就一个数字就不管他,如果有两个或两个以上就用第一个数字当父亲,让后面其他的数字与其关联。
Description
In the Not-Spreading-Your-Sickness University (NSYSU), there are many student groups. Students in the same group intercommunicate with each other frequently, and a student may join several groups. To prevent the possible transmissions of SARS, the NSYSU collects the member lists of all student groups, and makes the following rule in their standard operation procedure (SOP).
Once a member in a group is a suspect, all members in the group are suspects.
However, they find that it is not easy to identify all the suspects when a student is recognized as a suspect. Your job is to write a program which finds all the suspects.
Input
A case with n = 0 and m = 0 indicates the end of the input, and need not be processed.
Output
Sample Input
100 4 2 1 2 5 10 13 11 12 14 2 0 1 2 99 2 200 2 1 5 5 1 2 3 4 5 1 0 0 0
Sample Output
4 1 1
下附代码:
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 #include<cmath> 5 #include<algorithm> 6 #include<queue> 7 #define INF 1000005 8 using namespace std; 9 int f[30005],mark[30005],mark1[30005]={0}; 10 int finding(int x) 11 { 12 if(x!=f[x]) 13 f[x]=finding(f[x]); 14 return f[x]; 15 } 16 int together(int x,int y) 17 { 18 int f1=finding(x); 19 int f2=finding(y); 20 if(f1!=f2) 21 {f[f2]=f1;return 1;} 22 return 0; 23 } 24 int main() 25 { 26 int i,m,n,ans,t,bg,j,num,k,h=0,cot=0,sum,late,temp; 27 while(scanf("%d%d",&n,&m)&&(n!=0||m!=0)) 28 { 29 for(i=0;i<=n;i++) 30 f[i]=i; 31 k=0; 32 while(m--) 33 { 34 scanf("%d",&num); 35 if(num>1) 36 { 37 scanf("%d",&bg); 38 if(!mark1[bg]) 39 {mark[k++]=bg;mark1[bg]=1;} 40 for(i=1;i<num;i++) 41 { 42 scanf("%d",&late); 43 together(bg,late); 44 if(!mark1[late]) 45 {mark[k++]=late;mark1[late]=1;} 46 } 47 } 48 else if(num==1) 49 {scanf("%d",&temp); 50 if(!mark1[temp]) 51 {mark[k++]=temp;mark1[temp]=1;}} 52 } 53 sum=0; 54 for(i=0;i<k;i++) 55 { 56 if(finding(0)==finding(mark[i])) 57 sum++; 58 } 59 if(sum==0) 60 printf("1\n"); 61 else 62 printf("%d\n",sum); 63 for(i=0;i<k;i++) 64 mark1[mark[i]]=0; 65 } 66 return 0; 67 }
第六题:
一道超级水的最小生成树,用kruskal就可以。但是注意储存,只需要上三角就行。之前不小心数组开小了。就超了。。
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 #include<cmath> 5 #include<algorithm> 6 #include<queue> 7 #define INF 1000000 8 using namespace std; 9 int f[100005]; 10 struct node 11 { 12 int x; 13 int y; 14 int k; 15 }c[100005]; 16 int cmp(struct node a,struct node b) 17 { 18 return a.k<b.k; 19 } 20 int finding(int x) 21 { 22 if(f[x]!=x) 23 f[x]=finding(f[x]); 24 return f[x]; 25 } 26 int together(int x,int y) 27 { 28 int f1,f2; 29 f1=finding(x); 30 f2=finding(y); 31 if(f1!=f2) 32 {f[f2]=f1;return 1;} 33 return 0; 34 } 35 int main() 36 { 37 int i,m,n,ans,t,a,b,bg,j,num,k,h=0,sum=0; 38 while(scanf("%d",&n)!=EOF) 39 { 40 h=0;ans=0;sum=0; 41 for(i=0;i<100005;i++) 42 f[i]=i; 43 for(i=1;i<=n;i++) 44 for(j=1;j<=n;j++) 45 { 46 scanf("%d",&c[h].k); 47 if(c[h].k!=0) 48 { 49 c[h].x=i;c[h].y=j; 50 h++; 51 } 52 } 53 sort(c,c+h,cmp); 54 for(i=1;i<h;i++) 55 { 56 ans=together(c[i].x,c[i].y); 57 if(ans==1) 58 { 59 sum+=c[i].k; 60 } 61 } 62 printf("%d\n",sum); 63 } 64 return 0; 65 }
第七题:
这题是最短路径,用dijkstra会超的原因居然是模板错了!!。最后只能用floyd反而过了。。无语。。模板害死人啊。
if(s[j]==false&&dis[j]<mining)
{
u=j;mining=mapp[v][j];
}
这句才是真的
Description
When a driver has do drive from intersection A to the intersection B he/she tries to choose the route that will minimize the number of times he/she will have to change the switches manually.
Write a program that will calculate the minimal number of switch changes necessary to travel from intersection A to intersection B.
Input
Each of the following N lines contain a sequence of integers separated by a single blank character. First number in the i-th line, Ki (0 <= Ki <= N-1), represents the number of rails going out of the i-th intersection. Next Ki numbers represents the intersections directly connected to the i-th intersection.Switch in the i-th intersection is initially pointing in the direction of the first intersection listed.
Output
Sample Input
3 2 1 2 2 3 2 3 1 2 1 2
Sample Output
0
下附代码:
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 #include<cmath> 5 #include<algorithm> 6 #include<queue> 7 #define INF 1000000 8 using namespace std; 9 int mapp[105][105],dis[105]; 10 bool s[105]; 11 int n; 12 void dijkstra(int v) 13 { 14 int i,j; 15 for(i=1;i<=n;i++) 16 { 17 dis[i]=mapp[v][i]; 18 s[i]=false; 19 } 20 s[v]=true; 21 dis[v]=0; 22 for(i=2;i<=n;i++) 23 { 24 int mining=INF,u=v; 25 for(j=1;j<=n;j++) 26 { 27 if(s[j]==false&&dis[j]<mining) 28 { 29 u=j;mining=mapp[v][j]; 30 } 31 } 32 s[u]=true; 33 for(j=1;j<=n;j++) 34 { 35 if(s[j]==false&&mapp[u][j]<INF) 36 if(mapp[u][j]+dis[u]<dis[j]) 37 dis[j]=mapp[u][j]+dis[u]; 38 } 39 } 40 } 41 int main() 42 { 43 int i,m,ans,t,a,b,bg,j,num,k; 44 while(scanf("%d%d%d",&n,&a,&b)!=EOF) 45 {for(i=0;i<105;i++) 46 for(j=0;j<105;j++) 47 mapp[i][j]=INF; 48 for(i=1;i<=n;i++) 49 { 50 scanf("%d",&num); 51 for(j=0;j<num;j++) 52 { 53 scanf("%d",&bg); 54 if(j==0) 55 mapp[i][bg]=0; 56 else 57 mapp[i][bg]=1; 58 } 59 } 60 /*for(i=1;i<=n;i++) 61 {for(j=1;j<=n;j++) 62 printf("%d ",mapp[i][j]); 63 cout<<endl;}*/ 64 dijkstra(a); 65 /*for(j=1;j<=n;j++) 66 for(i=1;i<=n;i++) 67 for(k=1;k<=n;k++) 68 if(mapp[i][j]+mapp[j][k]<mapp[i][k]) 69 mapp[i][k]=mapp[i][j]+mapp[j][k];*/ 70 /*for(i=1;i<=n;i++) 71 printf("%d ",dis[i]); 72 cout<<endl;*/ 73 if(dis[b]==INF) 74 printf("-1\n"); 75 else 76 printf("%d\n",dis[b]); 77 /*if(mapp[a][b]==INF) 78 printf("-1\n"); 79 else 80 printf("%d\n",mapp[a][b]);*/ 81 } 82 return 0; 83 }
第八题:
这题以前做过,就是简单的素数筛一下,从小到大选择就好,注意。没有偶数。。我还调了半天。
Description
Every even number greater than 4 can be
written as the sum of two odd prime numbers.
For example:
8 = 3 + 5. Both 3 and 5 are odd prime numbers.
20 = 3 + 17 = 7 + 13.
42 = 5 + 37 = 11 + 31 = 13 + 29 = 19 + 23.
Today it is still unproven whether the conjecture is right. (Oh wait, I have the proof of course, but it is too long to write it on the margin of this page.)
Anyway, your task is now to verify Goldbach's conjecture for all even numbers less than a million.
Input
Each test case consists of one even integer n with 6 <= n < 1000000.
Input will be terminated by a value of 0 for n.
Output
Sample Input
8 20 42 0
Sample Output
8 = 3 + 5 20 = 3 + 17 42 = 5 + 37
下附代码:
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 #include<cmath> 5 #include<algorithm> 6 #include<queue> 7 #define INF 1000005 8 using namespace std; 9 queue<int>q; 10 int s[1000005]={0},primee[1000005]; 11 void prime() 12 { 13 int i,k=1,cot; 14 for(i=2;i<INF;i++) 15 { 16 if(s[i]==0) 17 primee[k++]=i; 18 cot=2; 19 while(cot*i<INF) 20 { 21 s[i*cot]=1; 22 cot++; 23 } 24 } 25 } 26 int main() 27 { 28 29 int i=1,n; 30 prime(); 31 //for(i=1;i<100;i++) 32 //cout<<primee[i]<<" "; 33 while(scanf("%d",&n)&&n!=0) 34 { 35 i=1; 36 while(s[n-primee[i]]) 37 { 38 i++; 39 } 40 printf("%d = %d + %d\n",n,primee[i],n-primee[i]); 41 } 42 return 0; 43 }
第九题:
简单的进位。字符串转成数字进行加减就好。
Description
Input
Output
Sample Input
123 456 555 555 123 594 0 0
Sample Output
No carry operation. 3 carry operations. 1 carry operation.
下附代码:
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 #include<cmath> 5 char a[200005],b[200005]; 6 int main() 7 { 8 int carry,ans,t,s; 9 while(scanf("%s%s",a,b)&&(a[0]!='0'||b[0]!='0')) 10 { 11 carry=0; 12 t=strlen(a)-1;s=strlen(b)-1;ans=0; 13 while(t>=0&&s>=0) 14 { 15 if((a[t]-48)+(b[s]-48)+carry>9) 16 { 17 carry=(a[t]-48)+(b[s]-48)+carry; 18 ans++; 19 carry/=10; 20 } 21 t--;s--; 22 } 23 if(t<0) 24 { 25 while(s>=0) 26 { 27 if((b[s]-48)+carry>9) 28 { 29 carry=(b[s]-48)+carry; 30 ans++;carry/=10;s--; 31 } 32 else 33 break; 34 } 35 } 36 if(s<0) 37 { 38 while(t>=0) 39 { 40 if((a[t]-48)+carry>9) 41 { 42 carry=(a[t]-48)+carry; 43 ans++;carry/=10;t--; 44 } 45 else 46 break; 47 } 48 } 49 if(ans==0) 50 printf("No carry operation.\n"); 51 else if(ans==1) 52 printf("1 carry operation.\n"); 53 else 54 printf("%d carry operations.\n",ans); 55 } 56 return 0; 57 }
第十题:
就是在n的范围内,互质的分数的个数。其实就是欧拉函数在1-n范围内求和,打个线性欧拉函数筛就搞定了。
Description
F2 = {1/2}
F3 = {1/3, 1/2, 2/3}
F4 = {1/4, 1/3, 1/2, 2/3, 3/4}
F5 = {1/5, 1/4, 1/3, 2/5, 1/2, 3/5, 2/3, 3/4, 4/5}
You task is to calculate the number of terms in the Farey sequence Fn.
Input
Output
Sample Input
2 3 4 5 0
Sample Output
1 3 5 9
下附代码:
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 #include<cmath> 5 #include<algorithm> 6 #include<queue> 7 #define INF 1000005 8 using namespace std; 9 int target[INF],phi[INF]; 10 bool pri[INF]; 11 int main() 12 { 13 int i,m,n,ans,t,bg,j,num,k,h=0,cot=0; 14 long long int sum=0; 15 for(i=2;i<INF;i++) 16 { 17 if(pri[i]==false) 18 { 19 target[cot++]=i; 20 phi[i]=i-1; 21 } 22 for(j=0;j<cot&&i*target[j]<INF;j++) 23 { 24 pri[i*target[j]]=true; 25 if(i%target[j]==0) 26 phi[i*target[j]]=phi[i]*target[j]; 27 else 28 phi[i*target[j]]=phi[i]*(target[j]-1); 29 } 30 } 31 while(scanf("%d",&n)&&n!=0) 32 { 33 sum=0; 34 for(i=2;i<=n;i++) 35 sum+=phi[i]; 36 printf("%lld\n",sum); 37 } 38 return 0; 39 }
其实还有两题。但都是比较困难的题目了。。待以后有余力的话继续补充。
又结束了一次训练,感觉还是没什么长进,希望暑假能提高代码能力。。加油!