Codeforces Round #738 (Div. 2) 题解(A-D1)
A. Mocha and Math
题目大意:
存在一个长度为 n n n的整数数组,可以选择任意一个区间 [ l , r ] [l,r] [l,r]对于所有的 i ( 0 ≤ i ≤ r − l ) i(0\le i\le r-l) i(0≤i≤r−l),将 a i a_i ai变成 a l + i & a r − i a_{l+i}\And a_{r-i} al+i&ar−i,这种操作可以执行无数次。
问整个数组中最大值能取到的最小值是多少。
解题思路:
其实这个操作看似很复杂,但我们都知道任何两个数 A & B ≤ min ( A , B ) A\And B\le \min(A,B) A&B≤min(A,B),所以无论选取那个区间执行操作都不会使得区间的最大值变大,那么对于每个数而言都可以跟其他的数 & \And &一次,所以每个数能取到的最小值就是所有数相与的结果。
所以答案就是所有整数与起来的结果。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=110;
int a[N];
int n;
int main()
{
int T;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
int res=a[1];
for(int i=2;i<=n;i++) res&=a[i];
printf("%d\n",res);
}
return 0;
}
B. Mocha and Red and Blue
题目大意:
给出一个长度为 n n n的字符串,要使得整个字符串的相邻字符相同的次数尽可能少的出现,字符串只由 B , R , ? B,R,? B,R,?三种构成,其中 ? ? ?表示这个字符可以由我们指定为 B B B和 R R R中的任意一种,输出最终的字符串。
解题思路:
首先我们能只能决定字符串中 ? ? ?的字符,如果对于一连串的 ? ? ?,我们肯定是选择采取BR两种字符间隔的构造字符串,那么这段字符串中间是不可能出现下相邻字符相同的,出现冲突的地方只有可能出现在两端。那我们只要根据某一端已经确定好的字符,选择与这个字符不同的作为起始字符构造就行了。
如果想要证明这种贪心做法是正确的,可以自己根据两头字符是否相同、连续 ? ? ?字符串的长度是奇是偶来分四种情况证明,这里就不再赘述了。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=110;
char s[N];
char a[2]={'B','R'};
int n;
void draw(int x,int c){
for(int i=x;i>=1;i--){
if(s[i]!='?') break;
s[i]=a[c];
c^=1;
}
}
void draw2(int x,int c){
for(int i=x,cnt=0;i<=n;i++){
if(s[i]!='?') break;
s[i]=a[c];
c^=1
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
scanf("%s",s+1);
char last='R';
int p=0;
for(int i=1;i<=n;i++){
if(s[i]!='?'){
draw(i-1,s[i]=='B');
last=s[i];
p=i;
}
}
if(s[n]=='?') draw2(p+1,last=='B');
printf("%s\n",s+1);
}
return 0;
}
C. Mocha and Hiking
题目大意:
图中存在 n + 1 n+1 n+1个点和 2 n + 1 2n +1 2n+1条有向边边。
n − 1 n-1 n−1条边是由 i i i指向 i + 1 i+1 i+1,其中 1 ≤ i ≤ n − 1 1\le i\le n-1 1≤i≤n−1。
其余的 n n n条边由一个长度为 n n n序列 a a a给出,如果 a i = 0 a_i=0 ai=0,那么就是由 i i i指向 n + 1 n+1 n+1,否则就是由 n + 1 n+1 n+1指向 i i i。
问能否从某个点出发不重不漏地经过所有点,输出具体的方案。
解题思路:
看到题的第一反应以为是欧拉路径,但其实这题跟欧拉路径没什么关系。
因为前n-1条边的原因,我们可以不重不漏的从 1 1 1走到 n n n。
那么我们只需要考虑将 n + 1 n+1 n+1这个点加入到 1 1 1到 n n n的所有情况就行了。
- n + 1 n+1 n+1作为起点,只需要有从 n + 1 n+1 n+1到 1 1 1的边就行了,即 a 1 = 1 a_1=1 a1=1。
- n + 1 n+1 n+1作为中间点插入到 i i i和 i + 1 i+1 i+1之间,那么只需要有 i → n + 1 i\rightarrow n+1 i→n+1和 n + 1 → i + 1 n+1\rightarrow i+1 n+1→i+1两条边就行了,即 a i = 0 , a i + 1 = 1 a_i=0,a_{i+1}=1 ai=0,ai+1=1。
- n + 1 n+1 n+1作为终点,只需要有一条从 n n n到 n + 1 n+1 n+1的边就行了,即 a n = 0 a_n=0 an=0。
如果这三种都行不通,就无解。
时间复杂度 O ( n ) O(n) O(n)
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+10;
int a[N];
int n;
int main()
{
int T;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
if(a[1]){
printf("%d ",n+1);
for(int i=1;i<=n;i++) printf("%d ",i);
puts("");
}
else{
int p=-1;
a[n+1]=1;
for(int i=1;i<=n;i++)
if(!a[i]&&a[i+1]){
p=i;
break;
}
if(p==-1) puts("-1");
else{
for(int i=1;i<=n;i++){
printf("%d ",i);
if(i==p) printf("%d ",n+1);
}
puts("");
}
}
}
return 0;
}
D. Mocha and Diana (Easy Version)
题目大意:
有两个由 n n n个顶点组成的图,其中两个图分别有 m 1 m_1 m1和 m 2 m_2 m2条初始边,对任意一个图进行加边的同时另一个图会加一条相同的边,问两个图中不出现的环前提下最多能加多少条边。
1 ≤ n ≤ 1000 1\le n \le 1000 1≤n≤1000
解题思路:
因为数据比较小,所以可以通过维护两个并查集,然后直接用 n 2 n^2 n2的暴力就行了。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1010;
int p1[N],p2[N];
int n,m1,m2;
int find(int x,int p[]){
if(p[x]!=x) p[x]=find(p[x],p);
return p[x];
}
int main()
{
scanf("%d%d%d",&n,&m1,&m2);
for(int i=1;i<=n;i++){
p1[i]=p2[i]=i;
}
while(m1--){
int a,b;
scanf("%d%d",&a,&b);
int fa=find(a,p1),fb=find(b,p1);
p1[fa]=fb;
}
while(m2--){
int a,b;
scanf("%d%d",&a,&b);
int fa=find(a,p2),fb=find(b,p2);
p2[fa]=fb;
}
vector<pair<int,int> > v;
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
int pa1=find(i,p1),pb1=find(j,p1);
int pa2=find(i,p2),pb2=find(j,p2);
if(pa1!=pb1&&pa2!=pb2){
v.push_back({i,j});
p1[pa1]=pb1;
p2[pa2]=pb2;
}
}
}
printf("%d\n",v.size());
for(auto i:v) printf("%d %d\n",i.first,i.second);
return 0;
}
本文详细解析了Codeforces Round #738 (Div.2)的四道题目,包括数组操作的最大值优化、字符串相邻字符匹配、图的路径规划以及有向图的增边问题。通过深入理解题意,运用贪心策略和并查集等算法,给出了高效的解题思路和代码实现,帮助读者提升编程竞赛解题能力。

119

被折叠的 条评论
为什么被折叠?



