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

 

posted @ 2018-02-03 20:53  粉兔  阅读(603)  评论(0编辑  收藏  举报