Codeforces Round #535 (Div. 3)
题意:每次询问给你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 }
题意:我们有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 }
题意:给你一个字符串,只由'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 }
题意:还是给你一个只由'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 }
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 }
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 }
题意:给你一个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 }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET开发智能桌面机器人:用.NET IoT库编写驱动控制两个屏幕
· 用纯.NET开发并制作一个智能桌面机器人:从.NET IoT入门开始
· 一个超经典 WinForm,WPF 卡死问题的终极反思
· ASP.NET Core - 日志记录系统(二)
· .NET 依赖注入中的 Captive Dependency
· 在外漂泊的这几年总结和感悟,展望未来
· 博客园 & 1Panel 联合终身会员上线
· 支付宝事故这事儿,凭什么又是程序员背锅?有没有可能是这样的...
· https证书一键自动续期,帮你解放90天限制
· 在 ASP.NET Core WebAPI如何实现版本控制?