【codeforces】【比赛题解】#920 Educational CF Round 37
【A】浇花
题意:
一个线段上每个整点都有花,有的点有自动浇花的喷水器,有问几秒能浇完所有的花。
题解:
大模拟
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define F(i,a,b) for(int i=(a);i<=(b);++i) 5 #define F2(i,a,b) for(int i=(a);i<(b);++i) 6 #define dF(i,a,b) for(int i=(a);i>=(b);--i) 7 #define dF2(i,a,b) for(int i=(a);i>(b);--i) 8 #include<cmath> 9 #include<iostream> 10 #include<vector> 11 #include<string> 12 #include<queue> 13 #include<set> 14 #include<map> 15 #define ll long long 16 #define eF(i,u) for(int i=h[u];i;i=nxt[i]) 17 using namespace std; 18 const int INF=0x3f3f3f3f; 19 inline int Abs(int X){return X<0?-X:X;} 20 inline int Gcd(int X,int Y){return Y?Gcd(Y,X%Y):X;} 21 inline ll Gcd(ll X,ll Y){return Y?Gcd(Y,X%Y):X;} 22 inline int Max(int X,int Y){return X<Y?Y:X;} 23 inline int Min(int X,int Y){return X<Y?X:Y;} 24 inline ll Max(ll X,ll Y){return X<Y?Y:X;} 25 inline ll Min(ll X,ll Y){return X<Y?X:Y;} 26 inline int Pow(int base,ll exp,int _mod){int _ans=1;for(;exp;exp>>=1,base=(ll)base*base%_mod)exp&1?_ans=(ll)_ans*base%_mod:0;return _ans;} 27 inline ll Pow(ll base,ll exp,ll _mod){ll _ans=1;for(;exp;exp>>=1,base=base*base%_mod)exp&1?_ans=_ans*base%_mod:0;return _ans;} 28 int n,q,Ans; 29 int a[100001],b[100001]; 30 int main(){ 31 int T; 32 scanf("%d",&T); 33 while(T--){ 34 Ans=0; 35 scanf("%d%d",&n,&q); 36 F(i,1,q) scanf("%d",a+i); 37 F(i,1,n){ 38 int k=999999999; 39 F(j,1,q){ 40 k=Min(k,Abs(i-a[j])); 41 } 42 Ans=Max(Ans,k); 43 } 44 printf("%d\n",Ans+1); 45 } 46 return 0; 47 }
【B】排队喝茶
题意:
有\(n\)个人排队喝茶,第\(i\)个人\(l_i\)时刻来排队,如果\(r_i\)时刻还没有排到他,他就走了,问每个人喝到茶的时间或者他没有喝到茶。
题解:
大模拟,每个人是否走了可以到他了再判断。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define F(i,a,b) for(int i=(a);i<=(b);++i) 5 #define F2(i,a,b) for(int i=(a);i<(b);++i) 6 #define dF(i,a,b) for(int i=(a);i>=(b);--i) 7 #define dF2(i,a,b) for(int i=(a);i>(b);--i) 8 #include<cmath> 9 #include<iostream> 10 #include<vector> 11 #include<string> 12 #include<queue> 13 #include<set> 14 #include<map> 15 #define ll long long 16 #define eF(i,u) for(int i=h[u];i;i=nxt[i]) 17 using namespace std; 18 const int INF=0x3f3f3f3f; 19 inline int Gcd(int X,int Y){return Y?Gcd(Y,X%Y):X;} 20 inline ll Gcd(ll X,ll Y){return Y?Gcd(Y,X%Y):X;} 21 inline int Max(int X,int Y){return X<Y?Y:X;} 22 inline int Min(int X,int Y){return X<Y?X:Y;} 23 inline ll Max(ll X,ll Y){return X<Y?Y:X;} 24 inline ll Min(ll X,ll Y){return X<Y?X:Y;} 25 inline int Pow(int base,ll exp,int _mod){int _ans=1;for(;exp;exp>>=1,base=(ll)base*base%_mod)exp&1?_ans=(ll)_ans*base%_mod:0;return _ans;} 26 inline ll Pow(ll base,ll exp,ll _mod){ll _ans=1;for(;exp;exp>>=1,base=base*base%_mod)exp&1?_ans=_ans*base%_mod:0;return _ans;} 27 int n,q; 28 int l[100001],r[100001],Ans[10001]; 29 int que[100001],L,R; 30 int main(){ 31 int T; 32 scanf("%d",&T); 33 while(T--){ 34 L=1, R=0; 35 scanf("%d",&n); 36 memset(Ans,0,sizeof Ans); 37 F(i,1,n) scanf("%d%d",l+i,r+i); 38 int i=1; 39 F(t,1,5000){ 40 while(l[i]==t) que[++R]=i, ++i; 41 while(L<=R&&r[que[L]]<t) ++L; 42 if(L<=R) Ans[que[L++]]=t; 43 } 44 F(j,1,n) printf("%d ",Ans[j]); puts(""); 45 } 46 return 0; 47 }
【C】交换相邻元素
题意:
一个1到n的排列,你可以交换某些相邻位置的值,问能否交换成上升序列。
题解:
连续的一串可以交换的,就表示这一串可以直接排序,那么我们把所有连续的一段都各自排序,看最终的数组是否升序即可。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define F(i,a,b) for(int i=(a);i<=(b);++i) 5 #define F2(i,a,b) for(int i=(a);i<(b);++i) 6 #define dF(i,a,b) for(int i=(a);i>=(b);--i) 7 #define dF2(i,a,b) for(int i=(a);i>(b);--i) 8 #include<cmath> 9 #include<iostream> 10 #include<vector> 11 #include<string> 12 #include<queue> 13 #include<set> 14 #include<map> 15 #define ll long long 16 #define eF(i,u) for(int i=h[u];i;i=nxt[i]) 17 using namespace std; 18 const int INF=0x3f3f3f3f; 19 inline int Gcd(int X,int Y){return Y?Gcd(Y,X%Y):X;} 20 inline ll Gcd(ll X,ll Y){return Y?Gcd(Y,X%Y):X;} 21 inline int Max(int X,int Y){return X<Y?Y:X;} 22 inline int Min(int X,int Y){return X<Y?X:Y;} 23 inline ll Max(ll X,ll Y){return X<Y?Y:X;} 24 inline ll Min(ll X,ll Y){return X<Y?X:Y;} 25 inline int Pow(int base,ll exp,int _mod){int _ans=1;for(;exp;exp>>=1,base=(ll)base*base%_mod)exp&1?_ans=(ll)_ans*base%_mod:0;return _ans;} 26 inline ll Pow(ll base,ll exp,ll _mod){ll _ans=1;for(;exp;exp>>=1,base=base*base%_mod)exp&1?_ans=_ans*base%_mod:0;return _ans;} 27 int n,q; 28 int a[200001],b[200001]; 29 int main(){ 30 scanf("%d",&n); 31 F(i,1,n) scanf("%d",a+i); 32 char ch; 33 F2(i,1,n) if((ch=getchar())!='1'&&ch!='0') --i; else b[i]=ch-'0'; 34 int lst=1; 35 F(i,1,n){ 36 if(!b[i]) sort(a+lst,a+i+1), lst=i+1; 37 } sort(a+lst,a+n+1); 38 F(i,1,n) if(a[i]!=i) {puts("NO"); return 0;} 39 puts("YES"); 40 return 0; 41 }
【D】水缸
题意:
有一些容量无限的水缸,初始时每个水缸中各自有一些水,你有一个容积为k的勺子,问你能否通过用勺子舀水让一个水缸中的水变成要求的V体积?
题解:
考虑把所有的水缸的水和要求的V体积都对勺子容积k取模。
那么如果有一些水缸中的水相加,再对k取模,等于V对k取模的结果,我们就确定最终的V体积的水来自这些水缸。
那么用\(f[i][j]\)表示前\(i\)个水缸中能否相加达到\(j\)容积(\(j\)对\(k\)取模)。
特别地,\(f[i][j]=1\)表示这一个水缸不需要选,\(f[i][j]=2\)表示这一个水缸可以选。
那么最终确定结果时可以反推回来,确定选取哪些水缸。
之后的事情主要是分类讨论,注意输出格式。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define F(i,a,b) for(int i=(a);i<=(b);++i) 5 #define F2(i,a,b) for(int i=(a);i<(b);++i) 6 #define dF(i,a,b) for(int i=(a);i>=(b);--i) 7 #define dF2(i,a,b) for(int i=(a);i>(b);--i) 8 #include<cmath> 9 #include<iostream> 10 #include<vector> 11 #include<string> 12 #include<queue> 13 #include<set> 14 #include<map> 15 #define ll long long 16 #define eF(i,u) for(int i=h[u];i;i=nxt[i]) 17 using namespace std; 18 const int INF=0x3f3f3f3f; 19 inline int Gcd(int X,int Y){return Y?Gcd(Y,X%Y):X;} 20 inline ll Gcd(ll X,ll Y){return Y?Gcd(Y,X%Y):X;} 21 inline int Max(int X,int Y){return X<Y?Y:X;} 22 inline int Min(int X,int Y){return X<Y?X:Y;} 23 inline ll Max(ll X,ll Y){return X<Y?Y:X;} 24 inline ll Min(ll X,ll Y){return X<Y?X:Y;} 25 inline int Pow(int base,ll exp,int _mod){int _ans=1;for(;exp;exp>>=1,base=(ll)base*base%_mod)exp&1?_ans=(ll)_ans*base%_mod:0;return _ans;} 26 inline ll Pow(ll base,ll exp,ll _mod){ll _ans=1;for(;exp;exp>>=1,base=base*base%_mod)exp&1?_ans=_ans*base%_mod:0;return _ans;} 27 int n,k,v; 28 int a[5001],b[5001],sum,s2; 29 int f[5001][5001]; 30 int Ans[5001]; 31 int main(){ 32 scanf("%d%d%d",&n,&k,&v); 33 F(i,1,n) scanf("%d",a+i), sum+=a[i], b[i]=a[i], a[i]%=k; 34 // F(i,1,n) printf("%d ",a[i]); puts(""); 35 if(sum<v) {puts("NO"); return 0;} 36 f[0][0]=1; 37 F(i,1,n){ 38 F2(j,0,k){ 39 if(f[i-1][j]){ 40 f[i][j]=1; 41 if(j+a[i]<k) f[i][j+a[i]]=2; 42 else f[i][j+a[i]-k]=2; 43 } 44 } 45 } 46 // F(i,1,n){ 47 // F2(j,0,k){ 48 // printf("%d ",f[i][j]); 49 // } 50 // puts(""); 51 // } 52 if(f[n][v%k]==0) puts("NO"); 53 else{ 54 puts("YES"); 55 int now=v%k; 56 int u=-1, unu=-1; 57 dF(i,n,1){ 58 if(f[i][now]==2) Ans[i]=1, now=(now-a[i]+k)%k; 59 } 60 // printf("ans:"); F(i,1,n) printf("%d ",Ans[i]); puts(""); 61 F(i,1,n) if(!Ans[i]) unu=i; else u=i; 62 // printf("u : %d, unu : %d\n",u,unu); 63 if(u==-1){ 64 F(i,2,n) if(b[i]>0) printf("%d %d 1\n",(b[i]-1)/k+1,i); 65 if(v>0) printf("%d 1 2\n",v/k); 66 } 67 else if(unu==-1){ 68 F(i,2,n) if(b[i]>0) printf("%d %d 1\n",(b[i]-1)/k+1,i); 69 if(sum-v>0) printf("%d 1 2\n",(sum-v)/k); 70 } 71 else{ 72 int s1=b[u],s2=b[unu]; 73 F(i,1,n){ 74 if(Ans[i]==1&&i!=u&&b[i]>0) printf("%d %d %d\n",(b[i]-1)/k+1,i,u), s1+=b[i]; 75 if(Ans[i]==0&&i!=unu&&b[i]>0) printf("%d %d %d\n",(b[i]-1)/k+1,i,unu), s2+=b[i]; 76 } 77 if(s2>=k) printf("%d %d %d\n",s2/k,unu,u); s1+=s2/k*k; 78 if(s1-v>=k) printf("%d %d %d\n",(s1-v)/k,u,unu); 79 } 80 } 81 return 0; 82 }
【E】连通分量?
题意:
从一个\(n\)个点的无向完全图中删去\(m\)条边,问现在图中连通分量个数和每个连通分量大小。
题解:
看了别人的博才发现这题其实非常简单暴力。
就是暴力BFS,不过下一个点要从还没到过的点的集合中枚举,就这么简单。
为什么不会TLE?我们算一下时间复杂度:
每个点都只会经过一次,也只会遍历一次。那么遍历当前点时,要花多少时间呢?
在剩下的点中枚举,就是枚举到没有删除的边就会把这个点加入队列吧,每个点只要加入了队列它就不会被再搜到,所以枚举点的复杂度是\(O(log\;n)\)的,因为我使用了STL的set容器。
但是如果搜到了被删除的边呢?这样的边可以保证只会被搜到最多2m次,从一条边的两端点出发。
那么最终复杂度是\(O(n(log\;n+log\;m))\),非常巧妙。
#include<cstdio> #define F(i,a,b) for(int i=(a);i<=(b);++i) #include<set> using namespace std; inline int Max(int X,int Y){return X<Y?Y:X;} inline int Min(int X,int Y){return X<Y?X:Y;} int n,m; set<int> vv; set<pair<int,int> > st; bool vis[200001]; int que[200001],l,r; int Ans[200001],ans; int main(){ scanf("%d%d",&n,&m); int x,y; F(i,1,m) scanf("%d%d",&x,&y), st.insert(make_pair(Min(x,y),Max(x,y))); F(i,1,n) vv.insert(i); F(i,1,n){ if(!vis[i]){ vis[i]=1; vv.erase(i); que[l=r=1]=i; while(l<=r){ int u=que[l++]; for(set<int>::iterator j=vv.begin();j!=vv.end();){ if(!st.count(make_pair(Min(u,*j),Max(u,*j)))) que[++r]=*j, vis[*j]=1, vv.erase(j++); else ++j; } } ++Ans[r]; ++ans; } } printf("%d\n",ans); F(i,1,n) while(Ans[i]--) printf("%d ",i); return 0; }