Codeforces Round #629 (Div. 3) 补题
这次div3打的过于自闭,各种进不去页面,各种WA,各种智障思路......
下次网络再卡试试这个,或者挂个梯子吧。
赛后看题解发现交上去的题似乎都想麻烦了,于是决定重补一遍,洗心革面,重新做人。
输入两个数a、b, 问a最少增加多少可以成为b的倍数。
假设a是kb+m,那么只需要增加b-m,即b-a%b,特判a%b==0即可。
1 #pragma GCC optimize(2) 2 #include<iostream> 3 #include<stdio.h> 4 #include<cstdio> 5 #include<string.h> 6 #include<algorithm> 7 #include<vector> 8 #include<queue> 9 #include<map> 10 #include<cmath> 11 #include<set> 12 #define INF 0x3f3f3f3f 13 typedef long long ll; 14 using namespace std; 15 inline void read(int &p) 16 { 17 p=0;int flag=1;char c=getchar(); 18 while(!isdigit(c)) {if(c=='-') flag=-1;c=getchar();} 19 while(isdigit(c)) {p=p*10+c-'0';c=getchar();}p*=flag; 20 } 21 int a,b,q; 22 int main() 23 { 24 #ifdef LOCAL 25 freopen("in.txt","r",stdin); 26 freopen("out.txt","w",stdout); 27 #endif 28 read(q); 29 while(q--){ 30 cin>>a>>b; 31 if(a%b==0){ 32 cout<<0<<endl; 33 } 34 else{ 35 cout<<b-a%b<<endl; 36 } 37 } 38 return 0; 39 }
长度为n的字符串,包含两个b,其余为a,求所有构成的字符串按字典序排序后第k个字符串。
比赛时的想法是先确定第一个b的位置,n是1e5,于是用了二分确定位置,然后再确定第二个b的位置就是容易的。在二分上浪费了巨多时间,还因为爆int交了两发wa,赛后看题解发现根本不用二分直接从右向左遍历即可,心态爆炸......
1 #pragma GCC optimize(2) 2 #include<iostream> 3 #include<stdio.h> 4 #include<cstdio> 5 #include<string.h> 6 #include<algorithm> 7 #include<vector> 8 #include<queue> 9 #include<map> 10 #include<cmath> 11 #include<set> 12 #define INF 0x3f3f3f3f 13 typedef long long ll; 14 using namespace std; 15 inline void read(int &p) 16 { 17 p=0;int flag=1;char c=getchar(); 18 while(!isdigit(c)) {if(c=='-') flag=-1;c=getchar();} 19 while(isdigit(c)) {p=p*10+c-'0';c=getchar();}p*=flag; 20 } 21 int q,n,k; 22 int main() 23 { 24 #ifdef LOCAL 25 freopen("in.txt","r",stdin); 26 freopen("out.txt","w",stdout); 27 #endif 28 read(q); 29 while(q--){ 30 int l,r; 31 read(n),read(k); 32 for(int i=n-1;i>=1;i--){ 33 if(k<=n-i){ 34 l=i; 35 r=n-k+1; 36 break; 37 } 38 k-=n-i; 39 } 40 for(int i=1;i<=n;i++){ 41 if(i==l||i==r){ 42 putchar('b'); 43 } 44 else{ 45 putchar('a'); 46 } 47 } 48 putchar('\n'); 49 50 } 51 return 0; 52 }
定义一种只包含0 1 2的数字,这种数字的xor运算为对应每一位的和mod3。给出这种数字x,求a b,使得a xor b==x,并且max(a,b)最小。
这道题比赛时思路应该是正确的,但是写的比较乱。按照每一位考虑,要得到0,需要0 0或者1 2,可以发现对于得到0选取0 0永远是最优的。要得到1需要1 0或2 2,遇到要得到1,我们选取1 0永远更优。要得到2,可以选取1 1和0 2。可以发现要得到1,对应位上的两个数有1 0和0 1的差别,得到2也有0 2,2 0,1 1的差别。这些都会对max(a,b)造成影响。我们只需要在第一次遇到1时给a对应位赋1,b对应位赋0,之后遇到1时给a对应位赋0,b对应位赋1。遇到1之前,遇到2时给a对应位赋1,b对应位赋1。遇到1之后,遇到2时给a对应位赋0,b对应位赋2,就可以使max(a,b)最小,不容易说明白,但其实观察样例就能发现。
1 #pragma GCC optimize(2) 2 #include<iostream> 3 #include<stdio.h> 4 #include<cstdio> 5 #include<string.h> 6 #include<algorithm> 7 #include<vector> 8 #include<queue> 9 #include<map> 10 #include<cmath> 11 #include<set> 12 #define INF 0x3f3f3f3f 13 typedef long long ll; 14 using namespace std; 15 inline void read(int &p) 16 { 17 p=0;int flag=1;char c=getchar(); 18 while(!isdigit(c)) {if(c=='-') flag=-1;c=getchar();} 19 while(isdigit(c)) {p=p*10+c-'0';c=getchar();}p*=flag; 20 } 21 int main() 22 { 23 #ifdef LOCAL 24 freopen("in.txt","r",stdin); 25 freopen("out.txt","w",stdout); 26 #endif 27 int q; 28 read(q); 29 while(q--){ 30 int n; 31 read(n); 32 string a,b; 33 char v; 34 bool flag=true; 35 for(int i=1;i<=n;i++){ 36 v=getchar(); 37 if(v=='2'){ 38 if(flag){ 39 a+='1'; 40 b+='1'; 41 } 42 else{ 43 a+='0'; 44 b+='2'; 45 } 46 } 47 else if(v=='0'){ 48 a+='0'; 49 b+='0'; 50 } 51 else{ 52 if(flag){ 53 a+='1'; 54 b+='0'; 55 flag=false; 56 } 57 else{ 58 a+='0'; 59 b+='1'; 60 } 61 } 62 } 63 cout<<a<<"\n"<<b<<'\n'; 64 } 65 return 0; 66 }
题意有点复杂,不重复了...
因为前面的智障思路,写到这道题的时候已经没什么时间了,并且这道题还想出了更智障的思路......
正解:首先容易想到最多只有3种颜色。如果所有数字都一样,那么只需要一种颜色;如果n是偶数,那么[1,2,1,2,...]一定是符合条件的;考虑n为奇数,如果存在两个相同的数字相邻,只需要把这两个数字看成一个数字,按照n为偶数染色就好了;否则,可以看作n个不同的数绕成一个环,前n-1个数按照偶数情况染色,最后一个数染成3就符合情况。
1 #pragma GCC optimize(2) 2 #include<iostream> 3 #include<stdio.h> 4 #include<cstdio> 5 #include<string.h> 6 #include<algorithm> 7 #include<vector> 8 #include<queue> 9 #include<map> 10 #include<cmath> 11 #include<set> 12 #define INF 0x3f3f3f3f 13 typedef long long ll; 14 using namespace std; 15 inline void read(int &p) 16 { 17 p=0;int flag=1;char c=getchar(); 18 while(!isdigit(c)) {if(c=='-') flag=-1;c=getchar();} 19 while(isdigit(c)) {p=p*10+c-'0';c=getchar();}p*=flag; 20 } 21 int main() 22 { 23 #ifdef LOCAL 24 freopen("in.txt","r",stdin); 25 freopen("out.txt","w",stdout); 26 #endif 27 int q; 28 read(q); 29 while(q--){ 30 int n; 31 read(n); 32 bool flag=true; 33 int pos=0; 34 int pre,now,f; 35 read(pre); 36 f=pre; 37 for(int i=2;i<=n;i++){ 38 read(now); 39 if(now==pre){ 40 pos=i-1; 41 } 42 else{ 43 flag=false; 44 } 45 pre=now; 46 } 47 if(flag){ 48 printf("1\n"); 49 for(int i=1;i<=n;i++) printf("1 "); 50 putchar('\n'); 51 } 52 else if(n%2==0){ 53 printf("2\n"); 54 for(int i=1;i<=n;i++) 55 if(i%2) printf("1 "); 56 else printf("2 "); 57 putchar('\n'); 58 } 59 else{ 60 if(pos){ 61 printf("2\n"); 62 for(int i=1;i<=pos;i++) 63 if(i%2) printf("1 "); 64 else printf("2 "); 65 for(int i=pos+1;i<=n;i++) 66 if(i%2) printf("2 "); 67 else printf("1 "); 68 putchar('\n'); 69 } 70 else{ 71 if(f==now){ 72 printf("2\n"); 73 for(int i=1;i<n;i++) 74 if(i%2) printf("1 "); 75 else printf("2 "); 76 printf("1 \n"); 77 } 78 else{ 79 printf("3\n"); 80 for(int i=1;i<n;i++) 81 if(i%2) printf("1 "); 82 else printf("2 "); 83 printf("3\n"); 84 } 85 } 86 } 87 } 88 return 0; 89 }
首先根据题意,如果一个节点的若干个儿子都是被询问的对象,那么只要这个节点在所选的路上,这几个被询问的节点就满足要求。所以问题可以转化为:所有被询问节点的父亲节点是否在一条路上。根据这样的思路,我们可以选取被询问节点中最深层的一个节点,其他节点都变成他们的父亲节点,那么只要我们选定的这个节点在其他所有节点的子树上,就可以满足条件。
采用dfs序维护这样的关系,首先将根节点压入栈中,并记录入栈时间tin[v],之后把他的所有子节点也压入栈,如此往复,每个节点在出栈时记录出栈时间tout[v]。在维护这样的关系的同时,我们顺便可以记录每个节点的深度与父亲节点。我们可以发现这样的关系:如果v是u的儿子,那么v比u后入栈,u比v后出栈,即tin[u]<=tin[v]&&tout[u]>=tout[v],这样我们就可以实现上述想法。根据题解还学会了vector的一些骚操作。
1 #pragma GCC optimize(2) 2 #include<iostream> 3 #include<stdio.h> 4 #include<cstdio> 5 #include<string.h> 6 #include<algorithm> 7 #include<vector> 8 #include<queue> 9 #include<map> 10 #include<cmath> 11 #include<set> 12 #define INF 0x3f3f3f3f 13 typedef long long ll; 14 using namespace std; 15 inline void read(int &p) 16 { 17 p=0;int flag=1;char c=getchar(); 18 while(!isdigit(c)) {if(c=='-') flag=-1;c=getchar();} 19 while(isdigit(c)) {p=p*10+c-'0';c=getchar();}p*=flag; 20 } 21 vector<int> p,d; 22 vector<int> tin,tout; 23 vector<vector<int> > tree; 24 int n,m,t; 25 void dfs(int v,int par,int deep){ 26 p[v]=par; 27 d[v]=deep; 28 tin[v]=t++; 29 for(int i=0;i<tree[v].size();i++){ 30 int to=tree[v][i]; 31 if(to==par) continue; 32 dfs(to,v,deep+1); 33 } 34 tout[v]=t++; 35 } 36 37 bool judge(int u,int v){ 38 return tin[u]>=tin[v]&&tout[u]<=tout[v]; 39 } 40 41 int main() 42 { 43 #ifdef LOCAL 44 freopen("in.txt","r",stdin); 45 freopen("out.txt","w",stdout); 46 #endif 47 read(n),read(m); 48 p=d=tin=tout=vector<int>(n); 49 tree=vector<vector<int> >(n); 50 for(int i=0;i<n-1;i++){ 51 int x,y; 52 read(x),read(y); 53 x--;y--; 54 tree[x].push_back(y); 55 tree[y].push_back(x); 56 } 57 dfs(0,-1,0); 58 while(m--){ 59 int k; 60 read(k); 61 vector<int> ver(k); 62 for(int i=0;i<k;i++){ 63 read(ver[i]); 64 ver[i]--; 65 } 66 int u=ver[0]; 67 for(int i=0;i<ver.size();i++){ 68 int _=ver[i]; 69 if(d[_]>d[u]) u=_; 70 } 71 for(int i=0;i<ver.size();i++){ 72 int _=ver[i]; 73 if(_==u||p[_]==-1) continue; 74 ver[i]=p[_]; 75 } 76 bool flag=true; 77 for(int i=0;i<ver.size();i++){ 78 int _=ver[i]; 79 if(!judge(u,_)){ 80 flag=false; 81 break; 82 } 83 } 84 if(flag) printf("YES\n"); 85 else printf("NO\n"); 86 } 87 return 0; 88 }
遍历数组中的每一种元素,求出k个数都变成该元素的最小步数,再求出整个数组的最小步数即可。首先将数组从小到大排序,并用一个pair类型数组维cnt护每种元素的个数cnt[i].first是元素值,cnt[i].second是元素个数。令val=cnt[i].first,那么要使k个数都变成val,数组中需要通过增大或减小变成val的元素数目为need=max(0,k-cnt[i].second)。要求出need个数需要的操作数,我们可以把need分为两部分,需要通过增大变成val的元素数目needl,需要通过减小变成val的元素数目needr。因为我们在维护cnt之前已经把原数组从小到大排序,所以needl个数都在i的左侧,needr个数都在i右侧。令prefcnt[i]为小于等于cnt[i].first的元素的数目,prefsum[i]为prefcnt[i]个数的和。可以先令needl=min(need,prefcnt[i-1]),needr=max(0,need-needl),那么needl个数要变成val,根据题目的变换规则,需要把i左侧的元素全部变成val-1,再让这needl个数加一,所需操作数为prefcnt[i-1]*(val-1)-presum[i-1]+needl,对于needr个数同样可以通过sufcnt数组和sufsum数组维护比cnt[i].first大的元素数目和它们的和。注意开long long。
过程比较繁琐,写完调bug也很心累....
1 #pragma GCC optimize(2) 2 #include<iostream> 3 #include<stdio.h> 4 #include<cstdio> 5 #include<string.h> 6 #include<algorithm> 7 #include<vector> 8 #include<queue> 9 #include<map> 10 #include<cmath> 11 #include<set> 12 #define INF 1e18 13 #define x first 14 #define y second 15 typedef long long ll; 16 using namespace std; 17 inline void read(int &p) 18 { 19 p=0;int flag=1;char c=getchar(); 20 while(!isdigit(c)) {if(c=='-') flag=-1;c=getchar();} 21 while(isdigit(c)) {p=p*10+c-'0';c=getchar();}p*=flag; 22 } 23 int main() 24 { 25 #ifdef LOCAL 26 freopen("in.txt","r",stdin); 27 freopen("out.txt","w",stdout); 28 #endif 29 int n,k; 30 read(n),read(k); 31 vector<int> a(n); 32 for(int i=0;i<n;i++) read(a[i]); 33 sort(a.begin(),a.end()); 34 vector<pair<int,int> > cnt; 35 for(int i=0;i<n;i++){ 36 if(cnt.empty()||cnt.back().x!=a[i]){ 37 cnt.push_back({a[i],1}); 38 } 39 else{ 40 cnt.back().y++; 41 } 42 } 43 vector<int> prefcnt,sufcnt; 44 vector<ll> prefsum,sufsum; 45 for(int i=0;i<cnt.size();i++){ 46 ll cursum=cnt[i].x*1ll*cnt[i].y; 47 int curcnt=cnt[i].y; 48 if(prefsum.empty()){ 49 prefcnt.push_back(curcnt); 50 prefsum.push_back(cursum); 51 } 52 else{ 53 prefcnt.push_back(prefcnt.back()+curcnt); 54 prefsum.push_back(prefsum.back()+cursum); 55 } 56 } 57 for(int i=cnt.size()-1;i>=0;i--){ 58 ll cursum=cnt[i].x*1ll*cnt[i].y; 59 int curcnt=cnt[i].y; 60 if(sufsum.empty()){ 61 sufcnt.push_back(curcnt); 62 sufsum.push_back(cursum); 63 } 64 else{ 65 sufsum.push_back(sufsum.back()+cursum); 66 sufcnt.push_back(sufcnt.back()+curcnt); 67 } 68 } 69 70 reverse(sufsum.begin(), sufsum.end()); 71 reverse(sufcnt.begin(), sufcnt.end()); 72 73 ll ans=INF; 74 for(int i=0;i<cnt.size();i++){ 75 int val=cnt[i].x; 76 int need=max(0,k-cnt[i].y); 77 int needl=0,needr; 78 ll curans=0; 79 if(i>0) needl=min(need,prefcnt[i-1]); 80 needr=max(0,need-needl); 81 if(i>0&&needl>0){ 82 curans+=(val-1)*1ll*prefcnt[i-1]-prefsum[i-1]; 83 curans+=needl; 84 } 85 if(i+1<cnt.size()&&needr>0){ 86 curans+=sufsum[i+1]-(val+1)*1ll*sufcnt[i+1]; 87 curans+=needr; 88 } 89 90 ans=min(ans,curans); 91 92 curans=0; 93 needr=0; 94 if(i+1<cnt.size()) needr=min(need,sufcnt[i+1]); 95 needl=max(0,need-needr); 96 if(i>0&&needl>0){ 97 curans+=(val-1)*1ll*prefcnt[i-1]-prefsum[i-1]; 98 curans+=needl; 99 } 100 if(i+1<cnt.size()&&needr>0){ 101 curans+=sufsum[i+1]-(val+1)*1ll*sufcnt[i+1]; 102 curans+=needr; 103 } 104 ans=min(ans,curans); 105 } 106 printf("%lld",ans); 107 return 0; 108 }
佛系补题,用时三天......

舒服了。。。

浙公网安备 33010602011771号