Codeforces Round #638 (Div. 2)
Posted kaike
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #638 (Div. 2)相关的知识,希望对你有一定的参考价值。
Codeforces Round #638 (Div. 2)
B. Phoenix and Beauty
正确解法:
n个数分别为ai,往里面任意加数(正数)使连续k个字串的和都相同。
如果n个数里面出现数的次数大于k,那么就不能成立。
如果n个数里面出现的数等于k,把这些数按一定顺序输出n次就可。
如果n个数里面出现的数小于k,往里面加1使其等于k。
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <algorithm> 5 #include <set> 6 #include <queue> 7 #include <stack> 8 #include <string> 9 #include <cstring> 10 #include <vector> 11 #include <map> 12 #include<ctime> 13 //#include <unordered_map> 14 #define mem( a ,x ) memset( a , x ,sizeof(a) ) 15 #define rep( i ,x ,y ) for( int i = x ; i<=y ;i++ ) 16 #define lson l ,mid ,pos<<1 17 #define rson mid+1 ,r ,pos<<1|1 18 using namespace std; 19 typedef long long ll ; 20 typedef pair<int ,int> pii; 21 typedef pair<ll ,int> pli; 22 const int inf = 0x3f3f3f3f; 23 const ll mod=998244353; 24 const int N=100000+50; 25 int T,n,k; 26 int a[110],bok[110],cnt=0,b[110],kkk=0; 27 int main() 28 { 29 scanf("%d",&T); 30 while(T--) 31 { 32 scanf("%d%d",&n,&k); 33 int maxx=0; 34 cnt=0; 35 kkk=0; 36 for(int i=1;i<=100;i++) 37 bok[i]=0; 38 for(int i=1;i<=n;i++) 39 { 40 scanf("%d",&a[i]); 41 bok[a[i]]++; 42 if(bok[a[i]]==1) cnt++; 43 } 44 if(cnt>k) 45 { 46 printf("-1 "); 47 continue; 48 } 49 while(cnt<k) 50 { 51 b[++kkk]=1; 52 cnt++; 53 } 54 for(int i=1;i<=n;i++) 55 if(bok[i]) 56 { 57 b[++kkk]=i; 58 } 59 printf("%d ",k*n); 60 while(n--) 61 { 62 for(int i=1;i<=kkk;i++) 63 printf("%d ",b[i]); 64 } 65 printf(" "); 66 } 67 68 69 return 0; 70 }
C. Phoenix and Distribution
正确解法:
把长度为n的字符串分成k个字符串,求其中最大的 最小字典序 的字符串。
当aabb分成2份时, ab ab
当aabbb 分成3份时, b是答案。 (ab/abb/a)都小于b
当前面的k个字母都不相同时,单独一个a[k]就是答案。(后面的字符串都可以加到第一个字母上去,总之比a[k]要小)
当前面k个字母都相同时:
当后面(k+1,n)个字母都不相同时,答案就为a(k,n)
当后面(k+1,n)个字母都相同时,平分字符串就好了。
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <algorithm> 5 #include <set> 6 #include <queue> 7 #include <stack> 8 #include <string> 9 #include <cstring> 10 #include <vector> 11 #include <map> 12 #include<ctime> 13 //#include <unordered_map> 14 #define mem( a ,x ) memset( a , x ,sizeof(a) ) 15 #define rep( i ,x ,y ) for( int i = x ; i<=y ;i++ ) 16 #define lson l ,mid ,pos<<1 17 #define rson mid+1 ,r ,pos<<1|1 18 using namespace std; 19 typedef long long ll ; 20 typedef pair<int ,int> pii; 21 typedef pair<ll ,int> pli; 22 const int inf = 0x3f3f3f3f; 23 const ll mod=998244353; 24 const int N=1e5+50; 25 int T,n,k; 26 char s[N],ss[N]; 27 int len=0,cnt=0; 28 29 int main() 30 { 31 scanf("%d",&T); 32 while(T--) 33 { 34 scanf("%d%d",&n,&k); 35 scanf("%s",s+1); 36 sort(s+1,s+n+1); 37 cnt=0; 38 for(int i=1;i<k;i++) 39 if(s[i]!=s[k]) 40 {cnt=1;break;} 41 if(cnt) 42 { 43 printf("%c ",s[k]); 44 continue; 45 } 46 for(int i=k+2;i<=n;i++) 47 if(s[i]!=s[k+1]) 48 {cnt=1;break;} 49 if(cnt) 50 { 51 printf("%c",s[k]); 52 for(int i=k+1;i<=n;i++) 53 printf("%c",s[i]); 54 printf(" "); 55 } 56 else 57 { 58 int res=(n-k)%k; 59 printf("%c",s[k]); 60 for(int i=1;i<=(n-k)/k;i++) 61 printf("%c",s[k+1]); 62 if(res) printf("%c",s[k+1]); 63 printf(" "); 64 } 65 } 66 67 return 0; 68 }
D. Phoenix and Science
正确解法:
第一天有1个细菌质量为1.
白天细菌可以不分裂,或者全部分裂,或者部分分裂。
晚上每个细菌增加质量为1.
求达到质量为n的最快天数 和每一天分裂的细胞数量。
如果分裂,增加的质量为2,不分裂,增加的质量为1
假设全部分裂,这是增加质量最快的方法。第n天就为 2^n 质量。
就把 1 2 4 …… 总和放进数组里面,再放进去一个 n-sum 。
排序一下,就是每天的细菌数量。
就是前面都是全部分裂,有一天部分分裂。后来都部分分裂。总和就能刚好为n。
每一天分裂的细胞数量就为 f[i]-f[i-1]
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <algorithm> 5 #include <set> 6 #include <queue> 7 #include <stack> 8 #include <string> 9 #include <cstring> 10 #include <vector> 11 #include <map> 12 #include<ctime> 13 //#include <unordered_map> 14 #define mem( a ,x ) memset( a , x ,sizeof(a) ) 15 #define rep( i ,x ,y ) for( int i = x ; i<=y ;i++ ) 16 #define lson l ,mid ,pos<<1 17 #define rson mid+1 ,r ,pos<<1|1 18 using namespace std; 19 typedef long long ll ; 20 typedef pair<int ,int> pii; 21 typedef pair<ll ,int> pli; 22 const int inf = 0x3f3f3f3f; 23 const ll mod=998244353; 24 const int N=1e5+50; 25 int n,lll[2*N],rrr[2*N]; 26 vector<pair<int,int> >ve[2*N]; 27 int ans[2*N],p[2*N]; 28 struct node 29 { 30 int id,val; 31 }tree[8*N]; 32 void build(int x,int l,int r) 33 { 34 if(l==r) 35 { 36 tree[x].id=p[l]; 37 tree[x].val=lll[p[l]]; 38 return ; 39 } 40 int mid=l+r>>1; 41 build(x<<1,l,mid); 42 build(x<<1|1,mid+1,r); 43 if(tree[x<<1].val>tree[x<<1|1].val) 44 tree[x]=tree[x<<1|1]; 45 else 46 tree[x]=tree[x<<1]; 47 } 48 pair<int,int>query(int rt,int l,int r,int L,int R) 49 { 50 if(L<=l&&r<=R) 51 { 52 return {tree[rt].val,tree[rt].id}; 53 } 54 int mid=l+r>>1; 55 pair<int,int>tmp1,tmp2; 56 tmp1.first=-1; 57 tmp2.first=-1; 58 if(mid>=L) tmp1=query(rt<<1,l,mid,L,R); 59 if(mid+1<=R) tmp2=query(rt<<1|1,mid+1,r,L,R); 60 if(tmp1.first==-1) return tmp2; 61 if(tmp2.first==-1) return tmp1; 62 if(tmp1.first>tmp2.first) return tmp2; 63 else return tmp1; 64 } 65 int main() 66 { 67 scanf("%d",&n); 68 for(int i=1;i<=n;i++) 69 { 70 scanf("%d%d",&lll[i],&rrr[i]); 71 ve[lll[i]].push_back({rrr[i],i}); 72 } 73 set<pair<int,int> >st; 74 for(int i=1;i<=n;i++) 75 { 76 st.insert(ve[i].begin(),ve[i].end()); 77 int y=(*st.begin()).second; 78 st.erase(st.begin()); 79 ans[y]=i; 80 p[i]=y; 81 } 82 /* for(int i=1;i<=n;i++) 83 cout<<ans[i]<<" "; 84 cout<<endl;*/ 85 build(1,1,n); 86 for(int i=1;i<=n;i++) 87 { 88 if(i+1>rrr[p[i]]) continue; 89 pair<int,int>k=query(1,1,n,i+1,rrr[p[i]]); 90 if(k.first<=i) 91 { 92 printf("NO "); 93 for(int i=1;i<=n;i++) 94 cout<<ans[i]<<" "; 95 cout<<endl; 96 swap(ans[p[i]],ans[k.second]); 97 for(int i=1;i<=n;i++) 98 cout<<ans[i]<<" "; 99 cout<<endl; 100 return 0; 101 } 102 } 103 printf("YES "); 104 for(int i=1;i<=n;i++) 105 cout<<ans[i]<<" "; 106 cout<<endl; 107 108 return 0; 109 }
E. Phoenix and Berries
正确解法:
有n棵树,每棵树上面有ai个红苹果和bi个蓝苹果。
每个篮子能装k个苹果,但是篮子只能装红苹果或者蓝苹果或者属于一颗树上面的苹果。
求最多能把多少个篮子装满。
根据贪心,我们应该选择尽可能多的颜色相同的苹果装进篮子里,对于一颗树来说,装不同颜色的篮子只可能有一个。其他都可以化成一个的情况。
设f[i][j]表示装完第i棵树时,剩下的红苹果的数量为j. 剩下蓝苹果的数量为 果实总数-f[i][j]*k-j.
设第i棵树的篮子由s1个红苹果和k-s1个蓝苹果组成。
未装的红苹果数量 num1=j+ai-s1 未装的蓝苹果数量为 num2=sum-f[i][j]*k-num1-k
f[i][num1%k]=max(f[i][num1%k],f[i-1][j]+num1/k+num2/k+1);
当这颗树不装不同颜色时 :
num1=j+a[i],num2=sum-f[i-1][j]*k-j-a[i];
f[i][num1%k]=max(f[i][num1%k],f[i-1][j]+num1/k+num2/k);
然后!!! int取模比ll 快一个常数,以后尽量用int 来取模,不然就可能会tle.
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <algorithm> 5 #include <set> 6 #include <queue> 7 #include <stack> 8 #include <string> 9 #include <cstring> 10 #include <vector> 11 #include <map> 12 #include<ctime> 13 //#include <unordered_map> 14 #define mem( a ,x ) memset( a , x ,sizeof(a) ) 15 #define rep( i ,x ,y ) for( int i = x ; i<=y ;i++ ) 16 #define lson l ,mid ,pos<<1 17 #define rson mid+1 ,r ,pos<<1|1 18 using namespace std; 19 typedef long long ll ; 20 typedef pair<int ,int> pii; 21 typedef pair<ll ,int> pli; 22 const int inf = 0x3f3f3f3f; 23 const ll mod=998244353; 24 const int N=100000+50; 25 int n,k; 26 int a[550],b[550]; 27 ll f[550][550],sum=0; 28 int num1,num2; 29 int main() 30 { 31 scanf("%d%d",&n,&k); 32 for(int i=1;i<=n;i++) 33 scanf("%d%d",&a[i],&b[i]); 34 memset(f,-1,sizeof(f)); 35 f[0][0]=0; 36 for(int i=1;i<=n;i++) 37 { 38 sum+=a[i]+b[i]; 39 for(int j=0;j<k;j++) 40 { 41 if(f[i-1][j]<0) continue; 42 for(int s1=1;s1<k&&s1<=a[i];s1++) 43 { 44 if(k-s1>b[i]) continue; 45 num1=j+a[i]-s1; 46 num2=sum-f[i-1][j]*k-num1-k; 47 f[i][num1%k]=max(f[i][num1%k],f[i-1][j]+num1/k+num2/k+1); 48 } 49 num1=j+a[i],num2=sum-f[i-1][j]*k-j-a[i]; 50 f[i][num1%k]=max(f[i][num1%k],f[i-1][j]+num1/k+num2/k); 51 } 52 } 53 ll ans=0; 54 for(int i=0;i<k;i++) 55 ans=max(ans,f[n][i]); 56 printf("%lld ",ans); 57 58 return 0; 59 }
F. Phoenix and Memory
正确解法:
1-n有一个特定的顺序,可是现在忘了顺序。
只记得每个数 在 l[i]-r[i] 之间。求特定顺序,并且看是否顺序唯一。
已知每个数范围,如何求特定顺序呢?
用ve[l].push_back({r,i});
看每个l 最小的那个区间,依次排序取值就可以了。
1 for(int i=1;i<=n;i++) 2 { 3 scanf("%d%d",&lll[i],&rrr[i]); 4 ve[lll[i]].push_back({rrr[i],i}); 5 } 6 set<pair<int,int> >st; 7 for(int i=1;i<=n;i++) 8 { 9 st.insert(ve[i].begin(),ve[i].end()); 10 int y=(*st.begin()).second; 11 st.erase(st.begin()); 12 ans[y]=i; 13 p[i]=y; 14 }
那么如何求唯一呢?
若 编号为2 的区间为[1,3] ,编号为3 的区间为 [1,3]
那么 2在1位置,3在2位置 。和 2在2位置,3在1位置都可以满足。
p[2]=1,p[3]=2; l[2]=1,r[2]=3; l[3]=1,r[3]=3;
得: l[p[j]] <= i < j <= r[p[i]]
得到结果:对于编号为i的来说,如果能找到一个编号属于 [i+1,r[p[i]]] 区间的 且 l[p[j]] <=i 那么就可以交换顺序。
当然只要 for 两次就可以得到。
但是会超时怎么办呢?
用线段树来维护。
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <algorithm> 5 #include <set> 6 #include <queue> 7 #include <stack> 8 #include <string> 9 #include <cstring> 10 #include <vector> 11 #include <map> 12 #include<ctime> 13 //#include <unordered_map> 14 #define mem( a ,x ) memset( a , x ,sizeof(a) ) 15 #define rep( i ,x ,y ) for( int i = x ; i<=y ;i++ ) 16 #define lson l ,mid ,pos<<1 17 #define rson mid+1 ,r ,pos<<1|1 18 using namespace std; 19 typedef long long ll ; 20 typedef pair<int ,int> pii; 21 typedef pair<ll ,int> pli; 22 const int inf = 0x3f3f3f3f; 23 const ll mod=998244353; 24 const int N=1e5+50; 25 int n,lll[2*N],rrr[2*N]; 26 vector<pair<int,int> >ve[2*N]; 27 int ans[2*N],p[2*N]; 28 struct node 29 { 30 int id,val; 31 }tree[8*N]; 32 void build(int x,int l,int r) 33 { 34 if(l==r) 35 { 36 tree[x].id=p[l]; 37 tree[x].val=lll[p[l]]; 38 return ; 39 } 40 int mid=l+r>>1; 41 build(x<<1,l,mid); 42 build(x<<1|1,mid+1,r); 43 if(tree[x<<1].val>tree[x<<1|1].val) 44 tree[x]=tree[x<<1|1]; 45 else 46 tree[x]=tree[x<<1]; 47 } 48 pair<int,int>query(int rt,int l,int r,int L,int R) 49 { 50 if(L<=l&&r<=R) 51 { 52 return {tree[rt].val,tree[rt].id}; 53 } 54 int mid=l+r>>1; 55 pair<int,int>tmp1,tmp2; 56 tmp1.first=-1; 57 tmp2.first=-1; 58 if(mid>=L) tmp1=query(rt<<1,l,mid,L,R); 59 if(mid+1<=R) tmp2=query(rt<<1|1,mid+1,r,L,R); 60 if(tmp1.first==-1) return tmp2; 61 if(tmp2.first==-1) return tmp1; 62 if(tmp1.first>tmp2.first) return tmp2; 63 else return tmp1; 64 } 65 int main() 66 { 67 scanf("%d",&n); 68 for(int i=1;i<=n;i++) 69 { 70 scanf("%d%d",&lll[i],&rrr[i]); 71 ve[lll[i]].push_back({rrr[i],i}); 72 } 73 set<pair<int,int> >st; 74 for(int i=1;i<=n;i++) 75 { 76 st.insert(ve[i].begin(),ve[i].end()); 77 int y=(*st.begin()).second; 78 st.erase(st.begin()); 79 ans[y]=i; 80 p[i]=y; 81 } 82 /* for(int i=1;i<=n;i++) 83 cout<<ans[i]<<" "; 84 cout<<endl;*/ 85 build(1,1,n); 86 for(int i=1;i<=n;i++) 87 { 88 if(i+1>rrr[p[i]]) continue; 89 pair<int,int>k=query(1,1,n,i+1,rrr[p[i]]); 90 if(k.first<=i) 91 { 92 printf("NO "); 93 for(int i=1;i<=n;i++) 94 cout<<ans[i]<<" "; 95 cout<<endl; 96 swap(ans[p[i]],ans[k.second]); 97 for(int i=1;i<=n;i++) 98 cout<<ans[i]<<" "; 99 cout<<endl; 100 return 0; 101 } 102 } 103 printf("YES "); 104 for(int i=1;i<=n;i++) 105 cout<<ans[i]<<" "; 106 cout<<endl; 107 108 return 0; 109 }
以上是关于Codeforces Round #638 (Div. 2)的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces Round #638 (Div. 2)
Codeforces Round #638 (Div. 2)
Codeforces Round #638 (Div. 2)
Codeforces Round #638 (Div. 2)(A~B)
Codeforces Round #638 (Div. 2) A~C题解
CF A. Phoenix and Balance Codeforces Round #638 (Div. 2) 5月1号