Codeforces Round #535 (Div. 3)

A. Two distinct points

题意:每次询问给你l1,r1,l2,r2,让你从区间[l1,r1]和区间[l2,r2]中各选出1个整数,使得这2个数不相同,输入保证l1<r1,l2<r2(也就是没有区间是只有1个数的)

题解:第一个区间选l1,然后判断l2是否等于l1,不等于就输出,等于就输出r(因为r2不可能等于l2)

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int T,l1,r1,l2,r2;
 4 int main()
 5 {
 6     scanf("%d",&T);
 7     while (T--)
 8     {
 9         scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
10         printf("%d ",l1);
11         if (l1!=l2) printf("%d\n",l2);else printf("%d\n",r2);
12     }
13 }
View Code

 

B. Divisors of Two Integers

题意:我们有2个数x,y,现在我们把他们所有的因数都写出来(不去重),例如6和12的就是,1,2,3,6,1,2,3,4,6,12 

        现在给你这个因数序列,让你反求x,y是多少,题目保证因子大小<=1e4

题解:我们显然可以发现,整个序列里最大的那个数一定是x(我们约定x>=y),找出x,然后再把x的所有因子剔除,剩下最大的就是y了

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n,x,f[12000];
 4 int main()
 5 {
 6     scanf("%d",&n);
 7     int y=-1;
 8     for (int i=1;i<=n;i++)
 9     {
10         scanf("%d",&x);
11         f[x]++;
12         y=max(y,x);
13     }
14     for (int i=y;i>=1;i--) if (y%i==0) f[i]--;
15     for (int i=y;i>=1;i--)
16          if (f[i]==1) {printf("%d %d",y,i);break;}
17 }
View Code

 

C. Nice Garland

题意:给你一个字符串,只由'R','G','B',三种字母构成,现在定义一个好串是满足,相同字母之间的位置差是3的非0倍数,

         也就是这3个字母形成一个循环,问你把原序列改成一个好串最少需要改几次,任意给出一种方案

题解:由于最近相同字母的位置差只可能是3,所以这个循环只有3!=6种,我们枚举这6种串,看哪一种少即可

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 int n,ans,a[7];
  4 char s[200005];
  5 int main()
  6 {
  7     scanf("%d",&n);
  8     scanf("%s",s+1);
  9     for (int i=1;i<=n;i++)
 10     {
 11         if (i%3==1) if (s[i]!='R') a[1]++;
 12         if (i%3==2) if (s[i]!='G') a[1]++;
 13         if (i%3==0) if (s[i]!='B') a[1]++;
 14     }
 15     for (int i=1;i<=n;i++)
 16     {
 17         if (i%3==1) if (s[i]!='R') a[2]++;
 18         if (i%3==2) if (s[i]!='B') a[2]++;
 19         if (i%3==0) if (s[i]!='G') a[2]++;
 20     }    
 21     for (int i=1;i<=n;i++)
 22     {
 23         if (i%3==1) if (s[i]!='B') a[3]++;
 24         if (i%3==2) if (s[i]!='G') a[3]++;
 25         if (i%3==0) if (s[i]!='R') a[3]++;
 26     }    
 27     for (int i=1;i<=n;i++)
 28     {
 29         if (i%3==1) if (s[i]!='B') a[4]++;
 30         if (i%3==2) if (s[i]!='R') a[4]++;
 31         if (i%3==0) if (s[i]!='G') a[4]++;
 32     }    
 33     for (int i=1;i<=n;i++)
 34     {
 35         if (i%3==1) if (s[i]!='G') a[5]++;
 36         if (i%3==2) if (s[i]!='B') a[5]++;
 37         if (i%3==0) if (s[i]!='R') a[5]++;
 38     }    
 39     for (int i=1;i<=n;i++)
 40     {
 41         if (i%3==1) if (s[i]!='G') a[6]++;
 42         if (i%3==2) if (s[i]!='R') a[6]++;
 43         if (i%3==0) if (s[i]!='B') a[6]++;
 44     }    
 45     int ans=2000000;
 46     for (int i=1;i<=6;i++)
 47     {
 48         ans=min(ans,a[i]);
 49     }
 50     cout<<ans<<endl;
 51     if (ans==a[1]) 
 52     {
 53         for (int i=1;i<=n;i++)
 54         {
 55             if (i%3==1) printf("R");
 56             if (i%3==2) printf("G");
 57             if (i%3==0) printf("B");
 58         }
 59     }else
 60     if (ans==a[2]) 
 61     {
 62         for (int i=1;i<=n;i++)
 63         {
 64             if (i%3==1) printf("R");
 65             if (i%3==2) printf("B");
 66             if (i%3==0) printf("G");
 67         }
 68     }else
 69     if (ans==a[3]) 
 70     {
 71         for (int i=1;i<=n;i++)
 72         {
 73             if (i%3==1) printf("B");
 74             if (i%3==2) printf("G");
 75             if (i%3==0) printf("R");
 76         }
 77     }else
 78     if (ans==a[4]) 
 79     {
 80         for (int i=1;i<=n;i++)
 81         {
 82             if (i%3==1) printf("B");
 83             if (i%3==2) printf("R");
 84             if (i%3==0) printf("G");
 85         }
 86     }else
 87     if (ans==a[5]) 
 88     {
 89         for (int i=1;i<=n;i++)
 90         {
 91             if (i%3==1) printf("G");
 92             if (i%3==2) printf("B");
 93             if (i%3==0) printf("R");
 94         }
 95     }else
 96     if (ans==a[6]) 
 97     {
 98         for (int i=1;i<=n;i++)
 99         {
100             if (i%3==1) printf("G");
101             if (i%3==2) printf("R");
102             if (i%3==0) printf("B");
103         }
104     }            
105 }
View Code

 

D. Diverse Garland

题意:还是给你一个只由'R','G','B'构成的字符串,现在的目标串是相邻的字母不同,还是问你至少改几次,任意给一种方案

题解:扫一次字符串,如果第i个字母和第i-1个字母一样,那么就看i+1的字母是什么,

         如果s[i]=s[i-1]=s[i+1]就把s[i]改成其他2个任意中的一个,如果不等于,那就改成除了s[i-1]和s[i+1]的另外一个

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n,ans,a[7];
 4 char s[200005];
 5 int main()
 6 {
 7     scanf("%d",&n);
 8     scanf("%s",s+1);
 9     s[n+1]=s[n];
10     for (int i=2;i<=n;i++)
11     {
12         if (s[i]==s[i-1])
13         {
14             if (s[i]=='B' && s[i+1]=='G') ans++,s[i]='R';else
15             if (s[i]=='B' && s[i+1]=='R') ans++,s[i]='G';else
16             if (s[i]=='B' && s[i+1]=='B') ans++,s[i]='G';else
17             if (s[i]=='R' && s[i+1]=='G') ans++,s[i]='B';else
18             if (s[i]=='R' && s[i+1]=='B') ans++,s[i]='G';else
19             if (s[i]=='R' && s[i+1]=='R') ans++,s[i]='G';else
20             if (s[i]=='G' && s[i+1]=='B') ans++,s[i]='R';else
21             if (s[i]=='G' && s[i+1]=='R') ans++,s[i]='B';else    
22             if (s[i]=='G' && s[i+1]=='G') ans++,s[i]='B';    
23         }    
24     }
25     printf("%d\n",ans);
26     for (int i=1;i<=n;i++) printf("%c",s[i]);    
27 }
View Code

 

E1. Array and Segments (Easy version)

题意:给你n(300)个数,还有m(300)个区间,你可以选择其中的某些区间(也可以不选),选到的区间里的每个数都减1,

        问如何选才能使,最后的序列里最大值-最小值最大

题解:我们显然可以发现,如果我们选择的区间覆盖了最后的最小值且没覆盖最大值,那我们的ans++,

                                      如果覆盖了最大值且没有覆盖最小值,那我们的ans--,

                                      如果都覆盖了,或者都没覆盖,那我们的ans一点影响也没有

      那我们发现其实,只要这个区间覆盖了最后的最小值,那么选这个区间就不亏

      所以我们可以枚举最后的最小值是谁,然后覆盖的所有区间都选上,最后得到最优答案

      时间复杂度是n*m*n的,如果使用差分统计则是n*n的

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n,m,a[505],id,ans,l[505],r[505],f[505],w[505],ansy,b[505];
 4 int main()
 5 {
 6     int why=0;
 7     scanf("%d%d",&n,&m);
 8     for (int i=1;i<=n;i++) 
 9     {
10         scanf("%d",&b[i]);
11     }
12     for (int i=1;i<=m;i++)
13             scanf("%d%d",&l[i],&r[i]);
14     for (int id=1;id<=n;id++)
15     {
16         for (int i=1;i<=n;i++) a[i]=b[i]; 
17         ans=0;
18         for (int i=1;i<=m;i++)
19         {    
20             if (l[i]<=id && r[i]>=id) 
21             {
22                 for (int j=l[i];j<=r[i];j++) a[j]--;
23                 ans++;
24                 f[ans]=i;
25             }
26         }
27         int tmin=5000000,tmax=-5000000;
28         for (int i=1;i<=n;i++)
29         {
30             tmin=min(tmin,a[i]);
31             tmax=max(tmax,a[i]);
32         }    
33         if (tmax-tmin>why)
34         {
35             why=tmax-tmin;
36             ansy=ans;
37             for (int i=1;i<=ans;i++) w[i]=f[i];
38         }
39     }
40     printf("%d\n%d\n",why,ansy);
41     for (int i=1;i<=ansy;i++)
42     {
43         printf("%d ",w[i]);
44     }
45 }
View Code

 

E2. Array and Segments (Hard version)

题意:还是和刚刚的E1一样,只不过现在我们的n是1e5的了,m还是300

        我们从刚刚的差分想起走,差分的意思是,在我们枚举了最后的最小值位置之后,看哪些区间可以被选择,此时用差分对这个区间进行减1的操作

        然后再全部扫一次数组,记录最大值和最小值,所以是n*n的

        最后的这次扫,只为了最值,却在循环里又浪费了一次n,可以从这里出发想到,

        如果我们用线段树来维护最大值最小值不就行了,枚举最后的最小值位置后,再枚举m次区间操作,看起来复杂度变成了n*m*logn

        但是实际写的时候你会发现,由于你每次枚举后,都要重新建树,这里还有一个代价,所以这样甚至还不如差分了!

        我们继续考虑继承,不难想到,我们枚举的时候,从i-1变到i的区间并不多(就是只包含i-1却不包含i的区间不会多,这意味着所有的也不超过300)

        那我们每次枚举后,可以先把只包含i-1的区间,重新+1,加回去,再操作以i开头的区间[i,x]们,这样就避免了重复重新建树

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 #define N 100005
  4 #define M 305 
  5 int n,m,a[N],l[M],r[M],ans[N];
  6 vector<int>add[N],sub[N];
  7 struct node
  8 {
  9     int l,r,maxx, minn, lazy;
 10 } tree[N*4];
 11 void push_up(int o)
 12 {
 13     tree[o].maxx=max(tree[o*2].maxx,tree[o*2+1].maxx);
 14     tree[o].minn=min(tree[o*2].minn,tree[o*2+1].minn);
 15 }
 16 void push_down(int o)
 17 {
 18     if (tree[o].l!=tree[o].r)
 19     {
 20         tree[o*2].maxx+=tree[o].lazy;tree[o*2].minn+=tree[o].lazy;
 21         tree[o*2+1].maxx+=tree[o].lazy;tree[o*2+1].minn+=tree[o].lazy;
 22         tree[o*2].lazy+=tree[o].lazy;
 23         tree[o*2+1].lazy+=tree[o].lazy;
 24     }
 25     tree[o].lazy=0;
 26 }
 27 void build(int o,int l,int r)
 28 {
 29     tree[o].l=l;
 30     tree[o].r=r;
 31     if (l==r)
 32     {
 33         tree[o].maxx=a[l];
 34         tree[o].minn=a[l];
 35         tree[o].lazy=0;
 36         return ;
 37     } 
 38     int mid=(l+r)/2;
 39     build(o*2,l,mid);
 40     build(o*2+1,mid+1,r);
 41     push_up(o);
 42 }
 43 
 44 void up(int o,int l,int r,int x)
 45 {
 46     if (tree[o].lazy!=0) push_down(o);
 47     tree[o].maxx+=x;
 48     tree[o].minn+=x;
 49     if (tree[o].l==l && tree[o].r==r)
 50     {
 51         tree[o].lazy+=x;
 52         return ;
 53     }
 54     int mid=(tree[o].l+tree[o].r)/2;
 55     if (r<=mid) up(o*2,l,r,x);
 56     else if(l>mid) up(o*2+1,l,r,x);
 57     else
 58     {
 59         up(o*2,l,mid,x);up(o*2+1,mid+1,r,x);
 60     }
 61     push_up(o);
 62 }
 63 int ask_max(int o,int l,int r)
 64 {
 65     if (tree[o].lazy) push_down(o);
 66     if (tree[o].l==l && tree[o].r==r) return tree[o].maxx;
 67     int mid=(tree[o].l + tree[o].r)/2,why;
 68     if (r<=mid) why=ask_max(o*2,l,r);
 69     else if(l>mid) why=ask_max(o*2+1,l,r);
 70     else why=max(ask_max(o*2,l,mid),ask_max(o*2+1,mid+1,r));
 71     return why;
 72 }
 73 int ask_min(int o,int l,int r)
 74 {
 75     if (tree[o].lazy) push_down(o);
 76     if (tree[o].l==l && tree[o].r==r) return tree[o].minn;
 77     int mid=(tree[o].l + tree[o].r)/2,why;
 78     if (r<=mid) why=ask_min(o*2,l,r);
 79     else if(l>mid) why=ask_min(o*2+1,l,r);
 80     else why=min(ask_min(o*2,l,mid),ask_min(o*2+1,mid+1,r));
 81     return why;
 82 }
 83 int main()
 84 {
 85     scanf("%d%d",&n,&m);
 86     for (int i=1;i<=n;i++) scanf("%d",&a[i]);
 87     for (int i=1;i<=m;i++)
 88     {
 89         scanf("%d%d",&l[i],&r[i]);
 90         sub[l[i]].push_back(i);
 91         add[r[i]].push_back(i);
 92     }
 93     build(1,1,n);
 94     int sum=-1,pid,tot=0;
 95     for (int i=1;i<=n;i++)
 96     {
 97         for (int j=0;j<add[i-1].size();j++)
 98         {
 99             int id=add[i-1][j];
100             up(1,l[id],r[id],1);
101         }
102         for (int j=0;j<sub[i].size();j++)
103         {
104             int id=sub[i][j];
105             up(1,l[id],r[id],-1);
106         }
107         int why=ask_max(1,1,n)-ask_min(1,1,n);
108         if (why>=sum)
109         {
110             sum=why;
111             pid=i;
112         }
113     }
114     printf("%d\n",sum);
115     for(int i=1;i<=m;i++) 
116         if(l[i]<=pid && pid<=r[i]) ans[++tot]=i;
117     printf("%d\n",tot);
118     for(int i=1;i<=tot;i++) printf("%d ",ans[i]); 
119     return 0;
120 }
View Code

 

F. MST Unification

题意:给你一个2e5个点,2e5条边的无向图,保证没有自环,2个点之间也只有1条边,你可以选择其中的一些边,让他们的权值+1或者翻倍,

         问你最少改几条边,使得这个图的最小生成树是唯一的

题解:我们回想kruskal的过程,我们把边排序后,从小开始选择,如果这条边的2个端点没联通,那么我们会考虑选择他,

        为什么我们说会考虑,因为我们一般只求最小生成树的大小,而不去在意他的长相,但在这里,我们显然可以想到,

        同样相同的权值的几条边,我们会优先选择哪一条呢?

        每一次我们先找到权值相同的那些边,然后开始选择,首先我们看他们2个端点是否已经联通,这样的边一定不会选,所以也一定不用改

        我们再扫一次,这一次看哪些边需要联通,且边同时就把他们联通了,选中的边就是选定成为生成树里的边,而此时那些还联通着的边且拥有相同权值的边,就应该改变

        有人会问,难道不可能是几条边的和一样吗,(1+2+5=2+2+4)类似的情况吗,我们还是回到kruskal,最小的一定会选的!而且2点之间也只有1条边,

       所以造成最小生成树不唯一的情况只会是有相同权值的边,同时可以被选择,选择一个后另一个就没用了这种情况

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 200006
 4 int n,m,fa[N],ans;
 5 struct rec
 6 {
 7     int x,y,z;
 8     bool operator <(const rec w) const {return z < w.z;}
 9 }a[N];
10 int get(int x) 
11 {
12     if (x==fa[x]) return x;
13     return fa[x]=get(fa[x]);
14 }
15 int main() 
16 {
17     scanf("%d%d",&n,&m);
18     for (int i=1;i<=m;i++) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
19     sort(a+1,a+m+1);
20     for (int i=1;i<=n;i++) fa[i]=i;
21     for (int i=1,j=1;i<=m;i=j) 
22     {
23         while (j<=m && a[j].z==a[i].z) j++;
24         int cnt=j-i;
25         for (int t=i;t<j;t++) 
26     {
27             int x=get(a[t].x),y=get(a[t].y);
28             if (x==y) cnt--;
29         }
30         for (int t=i;t<j;t++) 
31     {
32             int x=get(a[t].x),y=get(a[t].y);
33             if (x!=y) 
34             {
35         cnt--;
36                 fa[x]=y;
37             }
38         }
39         ans+=cnt;
40     }
41     printf("%d",ans);
42     return 0;
43 }
View Code
posted @ 2019-01-29 01:52  口香糖万岁  阅读(244)  评论(0编辑  收藏  举报