【codeforces】【比赛题解】#920 Educational CF Round 37

时间:2021-11-28 13:50:46

【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;
}