首页 > 代码库 > Codeforces Round #279 (Div. 2)
Codeforces Round #279 (Div. 2)
A. Team Olympiad
水题英文还这么长。。。
1 #include<bits/stdc++.h> 2 #define eps 1e-9 3 #define FOR(i,j,k) for(int i=j;i<=k;i++) 4 using namespace std; 5 typedef long long LL; 6 int i,j,k,n,m,x,y,T,ans,big,cas; 7 bool flag; 8 vector <int> a[5]; 9 int num,t;10 int main()11 {12 scanf("%d",&n);13 for (i=1;i<=n;i++)14 {15 scanf("%d",&t);16 a[t].push_back(i);17 }18 num=min((int)a[1].size(),(int)a[2].size());19 num=min(num,(int)a[3].size());20 printf("%d\n",num);21 for (i=0;i<num;i++)22 {23 printf("%d %d %d\n",a[1][i],a[2][i],a[3][i]);24 }25 return 0;26 }
B. Queue
有n个人排队,每个人都有一个编号,现给出每个人前边一人的编号和后边一人的编号(如果没有人则是0),求出原来队中人的顺序(输出编号)。
模拟,因为编号只有10^6,因此可以开两个10^6的数组,a[i][0]记录编号为i的人前边的前边的人的编号,a[i][1]记录编号为i的人后边的后边的人的编号。
显然从0开始能够确定偶数位置人的顺序,然后将他们标记为-1,再根据剩下的确定奇数位置的人的顺序即可。
1 #include<bits/stdc++.h> 2 #define eps 1e-9 3 #define FOR(i,j,k) for(int i=j;i<=k;i++) 4 using namespace std; 5 typedef long long LL; 6 int i,j,k,n,m,x,y,T,big,cas,a[1000006][2],st,l[200005],r[200005],ans[200005],temp; 7 bool flag; 8 int main() 9 {10 scanf("%d",&n);11 for (i=1;i<=n;i++)12 {13 scanf("%d%d",&l[i],&r[i]);14 a[r[i]][0]=l[i];15 a[l[i]][1]=r[i];16 }17 for (st=a[0][1],j=2;st!=0;j+=2)//确定偶数位置人 18 {19 ans[j]=st;20 temp=a[st][1];21 a[st][0]=-1;//已经确定位置的人标记为-1 22 a[st][1]=-1;23 st=temp;24 }25 for (i=1;i<=n;i++) 26 if (a[l[i]][0]==0) 27 {28 st=l[i];//找到奇数位置最前边的人 29 break;30 }31 ans[1]=st; 32 j=1;33 for (;st!=0;st=a[st][1],j+=2)//确定奇数位置的人 34 {35 ans[j]=st;36 }37 for (i=1;i<n;i++) printf("%d ",ans[i]);38 printf("%d\n",ans[n]);39 return 0;40 }
C. Hacking Cypher
给一个大数(长度10^6)问能够否分割成两个数,前边的能被a整除,后边的能被b整除,所有数不能有前导零。
模拟,取模的几个性质应该都懂吧,设某个数是def,那么def=d*100+e*10+f ,def mod n = ((d mod n)*(100 mod n)+(e mod n)*(10 mod n)+f mod n) mod n
设pre[i]为前i位能否整除a,suf[j]为后j为能否整除b。先预处理出pre和suf,显然pre[i]=true 并且 suf[i+1]=true的时候就是答案。
求suf的时候就可以通过前一位的pre值判断是否有解了,因此代码中没有开suf数组。
1 #include<bits/stdc++.h> 2 #define eps 1e-9 3 #define FOR(i,j,k) for(int i=j;i<=k;i++) 4 using namespace std; 5 typedef long long LL; 6 int i,j,k,n,m,x,y,T,ans,big,cas,a,b,len,w; 7 bool flag,pre[1000005]; 8 char s[1000005]; 9 int main()10 {11 scanf("%s",s);12 scanf("%d%d",&a,&b);13 len=strlen(s);14 for (i=0;i<len-1;i++)15 {16 x=(x*10+s[i]-‘0‘)%a;17 if (x==0)18 {19 pre[i]=true;20 }21 }22 w=1;x=0;23 for (i=len-1;i>0;i--)24 {25 x=(x+w*(s[i]-‘0‘))%b;26 w=w*10%b;27 if (x==0&&pre[i-1]&&s[i]!=‘0‘)28 {29 printf("YES\n");30 for (j=0;j<i;j++)31 {32 printf("%c",s[j]);33 }34 printf("\n");35 for (j=i;j<len;j++)36 {37 printf("%c",s[j]);38 }39 printf("\n");40 return 0;41 }42 }43 44 printf("NO\n");45 return 0;46 }
D. Chocolate
给两个巧克力,尺寸分别为a1*b1,a2*b2,现在想让它们的面积相同,有两种措施:
1.吃掉其中一个巧克力的一半
2.吃掉其中一个巧克力的1/3
并且剩下每次操作后剩余巧克力尺寸是整数,问至少操作几次。。。并输出最终巧克力的尺寸
先让a1,a2,b1,b2分别不断整除2再不断整除3,直到不能整除为止,如果最终的a1*b1不等于a2*b2,则说明无解,输出-1
(假设存在有解a1,b1,a2,b2,则由题目一定有a1*b1=a2*b2,a1*b1,a2*b2一定有相同的2的因子数和3的因子数,这时让它们不断整除2整除3,直到不能整除为止,a1*b1=a2*b2仍然成立)
设s1=a1*b1,s2=a2*b2,则如果s1/gcd(s1,s2)不等于s2/gcd(s1,s2),说明无解。
有解的时候s1‘=s2‘,一定有s1‘/gcd(s1‘,s2‘)=s2‘/gcd(s1‘,s2‘)=s1/gcd(s1,s2)=s2/gcd(s1,s2)
下面就是解这个式子:
s1*(1/2)x1*(2/3)y1 =s2*(1/2)x2*(2/3)y2 可以化简为
s1 =s2 * 2x1-x2-y1+y2 * 3y1-y2
找s1与s2关于2和3的因子数之差就能算出答案。
1 #include<bits/stdc++.h> 2 #define eps 1e-9 3 #define FOR(i,j,k) for(int i=j;i<=k;i++) 4 using namespace std; 5 typedef long long LL; 6 LL i,j,k,n,m,x,y,T,ans,big,cas,a[5],b[5],c[5],d[5],t,thr,two; 7 bool flag; 8 int main() 9 {10 for (i=1;i<=4;i++) scanf("%I64d",&a[i]);11 for (i=1;i<=4;i++)12 {13 t=a[i];14 while (t%2==0)15 {16 t/=2;17 b[i]++;//记录因子2的个数 18 }19 while (t%3==0)20 {21 t/=3;22 c[i]++;//记录因子3的个数 23 }24 d[i]=t;25 }26 if (d[1]*d[2]!=d[3]*d[4]) 27 {28 printf("-1\n");29 return 0;30 }31 thr=c[3]+c[4]-c[1]-c[2];32 if (thr>0)33 {34 t=thr;35 while (t>0&&a[3]%3==0)36 {37 a[3]=a[3]*2/3;38 t--;39 }40 while (t>0&&a[4]%3==0)41 {42 a[4]=a[4]*2/3;43 t--;44 }45 } else46 {47 t=-thr;48 while (t>0&&a[1]%3==0)49 {50 a[1]=a[1]*2/3;51 t--;52 }53 while (t>0&&a[2]%3==0)54 {55 a[2]=a[2]*2/3;56 t--;57 }58 }59 two=b[3]+b[4]-b[1]-b[2]+thr;//记得加上因除去因子3而多出来的因子2 60 61 if (two>0)62 {63 t=two;64 while (t>0&&a[3]%2==0)65 {66 a[3]=a[3]/2;67 t--;68 }69 while (t>0&&a[4]%2==0)70 {71 a[4]=a[4]/2;72 t--;73 }74 } else75 {76 t=-two;77 while (t>0&&a[1]%2==0)78 {79 a[1]=a[1]/2;80 t--;81 }82 while (t>0&&a[2]%2==0)83 {84 a[2]=a[2]/2;85 t--;86 }87 }88 printf("%I64d\n",abs(thr)+abs(two));89 printf("%I64d %I64d\n%I64d %I64d\n",a[1],a[2],a[3],a[4]);90 return 0;91 }
E. Restoring Increasing Sequence
给出严格递增的几个数,其中几个数的某几位不知道用符号?给出,输出一种方案。
分类讨论,这类题目写的好烦=。=#
首先讨论与上一位的长度(第一个数的上一位设为0)的关系,如果他们的长度相等再从头到尾递归扫描。
用dfs(i)=0表示到第i位是否需要向前边借位,比如数据:
pre=14349
now=14?4?
now的第5位的问号处只能是0,这时如果要满足题意,就一定要求now的前边4位组成的数 比 pre的前四位组成的数大,因此dfs(5)=1。
如果到递归第一个问号后仍然需要借位,则说明无解,比如:
pre=14949
now=14?49
第一个问号处dfs(3)=1,而前边两位的数不可能比pre的前两位大,因此输出NO。
其它的讨论细节乱搞一下,再乱搞乱搞。。。。还是详见代码吧:
1 #include<bits/stdc++.h> 2 #define eps 1e-9 3 #define FOR(i,j,k) for(int i=j;i<=k;i++) 4 using namespace std; 5 typedef long long LL; 6 int i,j,k,n,m,x,y,T,big,cas,last_len,len; 7 bool flag; 8 char last[10],s[10],bf[10],ans[100005][10]; 9 bool dfs(int x)//false为不需要进位,true表示需要进位 10 { 11 if (x>=len) return 1; 12 if (s[x]==‘?‘) 13 { 14 if (dfs(x+1)) 15 { 16 s[x]=last[x]; 17 if (last[x]==‘9‘) 18 { 19 s[x]=‘0‘; 20 return 1; 21 }else 22 { 23 s[x]=last[x]+1; 24 return 0; 25 } 26 }else 27 { 28 s[x]=last[x]; 29 return 0; 30 } 31 }else 32 { 33 if (s[x]>last[x]) 34 { 35 for (int i=x+1;i<len;i++) 36 { 37 if (bf[i]==‘?‘) s[i]=‘0‘; 38 } 39 return 0; 40 }else 41 if (s[x]<last[x]) 42 { 43 for (int i=x+1;i<len;i++) 44 { 45 if (bf[i]==‘?‘) s[i]=‘0‘; 46 } 47 return 1; 48 }else 49 { 50 return dfs(x+1); 51 } 52 } 53 } 54 55 56 int main() 57 { 58 scanf("%d",&n); 59 strcpy(last,"0"); last_len=0; 60 for (i=1;i<=n;i++) 61 { 62 scanf("%s",s); 63 len=strlen(s); 64 if (last_len>len) 65 { 66 printf("NO\n"); 67 return 0; 68 }else 69 if (last_len<len) 70 { 71 if (s[0]==‘?‘) s[0]=‘1‘; 72 for (j=1;j<len;j++) 73 { 74 if (s[j]==‘?‘) 75 { 76 s[j]=‘0‘; 77 } 78 } 79 strcpy(ans[i],s); 80 last_len=len; 81 strcpy(last,s); 82 }else 83 { 84 strcpy(bf,s); 85 if (dfs(0)) 86 { 87 printf("NO\n"); 88 return 0; 89 }else 90 { 91 strcpy(ans[i],s); 92 last_len=len; 93 strcpy(last,s); 94 } 95 } 96 } 97 printf("YES\n"); 98 for (i=1;i<=n;i++) 99 {100 printf("%s\n",ans[i]);101 }102 return 0;103 }
F. Treeland Tour
给一棵最多6000个结点的树,每个点有权值,求其中的一条链,使得LIS的序列和最大。
网上有人竟然枚举起点+求LIS o(N^2logN) 通过了,醉了,看来数据是很水了,在board上点开看了几个人的代码也是这样写的,不知道正解是怎样
啊,第一场做出5道题的CF比赛,第一次排名这么靠前,只是不算rating。。。截个图
Codeforces Round #279 (Div. 2)