Codeforces Round #738(Div.2)
比赛链接:https://codeforces.com/contest/1559
A - Mocha and Math
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
/*因为操作次数是任意的,每次一个数&上另一个数肯定是会变小的,
那么最小的最大值值就是所有数&起来。 */
using namespace std ;
const int N = 105;
int n,a[N];
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
int ans=0;
scanf("%d", &n);
for (int i = 0; i < n; i ++ ) scanf("%d", &a[i]);
int res=a[0];
for (int i = 1; i < n; i ++ )
{
res=res&a[i];
}
printf("%d\n",res);
}
return 0 ;
}
B - Mocha and Red and Blue
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
char a[110];
int main() {
int T;
cin >> T;
while (T--)
{
int n;
cin>>n;
scanf("%s", a+1); //将字符串存在1~n
int pos=-1;
for (int i = 1; i <= n; i ++ )
if(a[i]!='?') //找到第一个不是问号的字符串的位置
{
pos=i;
break;
}
if(pos==-1) //pos=-1代表所有字符串都是问号
{
for(int i=1;i<=n;i++)
{
if(i&1) a[i]='B';
else a[i]='R';
cout<<a[i];
}
}
else
{
for(int i=pos-1;i>=1;i--) //从第一个不是问号的字符串前一个位置向前遍历
if(a[i+1]=='B') a[i]='R'; //与后面一个取相反的
else a[i]='B';
for(int i=1;i<pos;i++) cout<<a[i]; //输出前pos-1个
for(int i=pos;i<=n;i++)
{
if(a[i]=='?')
{
if(a[i-1]=='B') a[i]='R';
else a[i]='B';
}
cout<<a[i];
}
}
puts("");
}
return 0;
}
C - Mocha and Hiking
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 10010;
int a[N];
int main() {
int T;
cin>>T;
while(T--)
{
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);
bool flag=false; //如果最后flag=false表示无解
int pos=-1; //记录插入n+1的位置
for (int i = 2; i <= n; i ++ )
if(a[i] && !a[i-1]) //遍历,寻找是否有可以插入n+1的位置(在i-1和i之间)
{
pos=i;
break;
}
if(a[1]) //如果n+1号点可以向1号点连一条边
{
flag=true;
cout<<n+1<<' ';
for(int i = 1; i <= n; i ++ ) cout<<i<<' ';
}
else if(a[n]==0) //如果n号点可以向n+1号点连一条边
{
flag=true;
for(int i = 1; i <= n; i ++ ) cout<<i<<' ';
cout<<n+1;
}
else if(pos!=-1) //或者如果1~n中有位置可以插入n+1
{
flag=true;
for (int i = 1; i <= n; i ++ )
{
if(i==pos) cout<<n+1<<' ';
cout<<i<<' ';
}
}
if(!flag) puts("-1");
puts("");
}
return 0;
}
D1 - Mocha and Diana (Easy Version)
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
//并查集裸题,n^2遍历所有边,每次判断是否可以同时加入到两棵树中即可
using namespace std;
typedef pair<int, int> PII;
const int N = 10010;
int n,m1,m2;
int p1[N],p2[N];
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]=i;
for (int i = 1; i <= n; i ++ ) p2[i]=i;
int u,v;
for (int i = 0; i < m1; i ++ )
{
scanf("%d%d", &u, &v);
u=find(u,p1),v=find(v,p1);
if(u!=v) p1[u]=v;
//注意!此处一定要判断根节点是否相同,因为已有边会出现相同一点,如:(2,5),(2,9),这时就会
//出现前面这个点被加到一个集合中,后面又被加到另一个集合中的情况,会WA(惨痛教训!)
}
for (int i = 0; i < m2; i ++ )
{
scanf("%d%d", &u, &v);
u=find(u,p2),v=find(v,p2);
if(u!=v) p2[u]=v;
}
int res=0;
vector<PII> ans; //用vector+pair来存边
for (int i = 1; i <= n; i ++ ) //暴力枚举所有边
for (int j = i + 1; j <= n; j ++ )
{
int a,b,c,d;
a=find(i,p1),b=find(j,p1),c=find(i,p2),d=find(j,p2);
if(a!=b && c!=d)
{
p1[a]=b;
p2[c]=d;
res++;
ans.push_back({i,j});
}
}
cout<<res<<endl;
for(PII i:ans) cout<<i.first<<' '<<i.second<<endl;
return 0;
}
D2 - Mocha and Diana (Hard Version)
D2与D1题意完全一致,只是数据范围扩大了,导致我们不能再用n^2的方法去暴力,参考巨巨们的题解知道了一种解法,即在所有节点中选择一点作为根节点(我这里选择的是1),先O(n)遍历所有节点,判断在树1和树2中是否都可以合并到根节点,可以的话在该节点和根节点间连一条边并输出,然后剩下的就是两种情况:只在树1中可以合并到根节点和只在树2中可以合并到根节点,于是我们O(n)遍历,将这些节点分别存入两个数组res1、res2,最后进行两两配对连接起来(最大配对数量为两数组中较小的那个)。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 100010;
int n,m1,m2;
int p1[N],p2[N];
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]=i;
for (int i = 1; i <= n; i ++ ) p2[i]=i;
int u,v;
for (int i = 0; i < m1; i ++ )
{
int l,r;
scanf("%d%d", &u, &v);
l=find(u,p1),r=find(v,p1);
if(l!=r)
{
if(l<r) p1[r]=l;
else p1[l]=r;
} //让较小的节点当父节点,以保证之后在有1的集合中1为祖宗节点
}
for (int i = 0; i < m2; i ++ )
{
int l,r;
scanf("%d%d", &u, &v);
l=find(u,p2),r=find(v,p2);
if(l!=r)
{
if(l<r) p2[r]=l;
else p2[l]=r;
}
}
int res=0;
vector<int> res1,res2;
cout<<n-1-max(m1,m2)<<endl; //最大连接边数为总边数减去两棵树中已连边数最大值
for (int i = 2; i <= n; i ++ ) //必须先将两张图中均不在1这棵树上的点并入1这个集合
{
int a,b;
a=find(i,p1),b=find(i,p2);
if(1!=a && 1!=b)
{
p1[a]=1;
p2[b]=1;
cout<<1<<' '<<i<<endl;
}
}
/*遍历2~n,将只在树1上的点和只在树2上的点连接起来得到最终答案
(一张图连上了1,另一张没有连上1,那么这时的点i有可能与接下来某个点j连接,
从而使它合理地连上1,所以这里把它存进栈里。)
*/
for (int i = 2; i <= n; i ++ )
{
int a,b;
a=find(i,p1),b=find(i,p2);
if(1!=a)
{
res1.push_back(i);
p1[a]=1;
}
else if(1!=b)
{
res2.push_back(i);
p2[b]=1;
}
}
int rlength=min(res1.size(),res2.size());
for(int i=0;i<rlength;i++)
cout<<res1[i]<<' '<<res2[i]<<endl;
return 0;
}
E - Mocha and Stars