Codeforces Round #738 (Div. 2)(A,B,C,D1,D2)


A. Mocha and Math

题目大意:
给出一个数组,你可以在任意大小的区间(大小不能为1)进行一个操作,区间元素与颠倒后的区间元素按位与,
[ l , r ];
a[l]=a[l]&a[r]
a[l+1]=a[l+1]&a[r-1]…
问经过任意次操作后数组中的最小值可能是多少

思路:
因为按位与的特性是只要有一个0就是0
可以知道我们可以通过操作使其中任意两个数按位与
那么最小值当然就是所有数的与和,把0尽可能的多

AC代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#define ll long long 
using namespace std;
const int maxn = 1e6+7;
int a[maxn];
int main() {
	int T;
	scanf("%d", &T);
	while (T--) {
		int n;
		scanf("%d", &n);
		int ans = 0;
		for (int i = 1; i <= n; ++i) {
			scanf("%d", &a[i]);
			if (i == 1)ans = a[i];
			else ans &= a[i];
		}
		printf("%d\n",ans);
	}
}

B. Mocha and Red and Blue

题目大意:
尽可能的使相邻的字符相同的情况最少,字符只可能是B或者R
?是可以自己填的情况,问相邻字符相同最少的情况

思路:
优先放B贪心走一遍
再优先放R贪心走一遍
取最小的情况

AC代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#define ll long long 
using namespace std;
const int maxn = 1e6+7;
char a[maxn],b[maxn];
int main() {
	int T;
	scanf("%d", &T);
	while (T--) {
		int n;
		scanf("%d", &n);
		getchar();
		int cnt1 = 0, cnt2 = 0;
		for (int i = 1; i <= n; ++i) {
			scanf("%c", &a[i]);
			b[i] = a[i];
			if (a[i] == '?') {
				if (a[i - 1] == 'B')a[i] = 'R';
				else a[i] = 'B';
			}
		}
		for (int i = 1; i <= n;++i) {
			if (a[i] == a[i - 1])cnt1++;
		}
		for (int i = 1; i <= n; ++i) {
			if (b[i] == '?') {
				if (b[i - 1] == 'R')b[i] = 'B';
				else b[i] = 'R';
			}
		}
		for (int i = 1; i <= n; ++i) {
			if (b[i] == b[i - 1])cnt2++;
		}
		if(cnt1<=cnt2)for (int i = 1; i <= n; ++i)printf("%c", a[i]);
		else for (int i = 1; i <= n; ++i)printf("%c", b[i]);
		printf("\n");
	}
}

C. Mocha and Hiking

题目大意:
有n+1个点,2*n-1条边
第一种边
1到n相邻的相连,注意只是1到n,没有n+1
第二种边
如果ai为0则是一条i到n+1的边
如果ai为1则是一条n+1到i的边
要求每点经过一次,输出路径,不能则输出-1
起点任意

思路:
由于多了一个n+1节点
我们称1到n为主路线
我们有3种方式可以走完所有点
一种是从1开始,主路线中有a[i] = 0,a[i+1] = 1的情况,这样我们就可以先到n+1再返回主路线
第二种是从1开始,主路线后再到n+1的情况,要求a[n]=0
第三种是从n+1开始,在到主路线

AC代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#define ll long long 
using namespace std;
const int maxn = 1e6+7;
int a[maxn];
struct e_node {
	int next;
	int to;
}e[maxn<<1];
int tot;
int head[maxn];
void add_e(int u,int v) {
	e[++tot].to = v;
	e[tot].next = head[u];
	head[u] = tot;
}
int ans[maxn];
int vis[maxn];
void dfs(int u,int k) {
	vis[u] = 1;
	for (int i = head[u]; i;i=e[i].next) {
		int v = e[i].to;
		dfs(v,k+1);
	}
	vis[u] = 0;
}
int main() {
	int T;
	scanf("%d", &T);
	while (T--) {
		int n;
		scanf("%d", &n);
		int flag = 0;
		int ansflag = 0;
		for (int i = 1; i <= n; ++i) {
			scanf("%d", &a[i]);
			if (ansflag)continue;
			if (i == 1) {
				if (a[1] == 1) {
					printf("%d ", n + 1);
					for (int j = 1; j <= n; ++j) {
						printf("%d ", j);
					}
					printf("\n");
					ansflag = 1;
				}
			}
			else if (a[i - 1] == 0 && a[i] == 1) {
				for (int j = 1; j <= i - 1; ++j) {
					printf("%d ", j);
				}
				printf("%d ",n+1);
				for (int j = i; j <= n; ++j) {
					printf("%d ",j);
				}
				printf("\n");
				ansflag = 1;
			}
			if (i == n && a[i] == 0) {
				for (int j = 1; j <= n; ++j) {
					printf("%d ", j);
				}
				printf("%d\n", n + 1);
				ansflag = 1;
			}	
		}
		if (!ansflag)printf("-1\n");
	}
}

D1. Mocha and Diana (Easy Version)

题目大意:
给你两个森林,每个森林都有他的初始边,你可以同时给两个森林添加任意边,使添加完后还是森林(不能有环)
问最多能添加哪些边
n为节点数,范围1000

思路:
两个并查集,暴力枚举每两节点之间能否添加边,如果在两个森林中,这两个节点都不在一个集合内,则添加。
至于为什么要两个森林里这两个节点都不在一个集合里,是因为如果有一个森林这两个节点已经在一个集合里了,会造成环

AC代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#define ll long long 
using namespace std;
const int maxn = 1e6+7;
int fa1[maxn], fa2[maxn];
int f1[maxn][2],f2[maxn][2];
int n, m1, m2;
int find_fa1(int x) { return x == fa1[x] ? x : fa1[x] = find_fa1(fa1[x]); }
void add_fa1(int x,int y) {
	int u = find_fa1(x);
	int v = find_fa1(y);
	fa1[v] = u;
}
int find_fa2(int x) { return x == fa2[x] ? x : fa2[x] = find_fa2(fa2[x]); }
void add_fa2(int x, int y) {
	int u = find_fa2(x);
	int v = find_fa2(y);
	fa2[v] = u;
}
int tot;
int ans[maxn][2];
int main() {
	scanf("%d %d %d",&n,&m1,&m2);
	int q1 = 0,q2=0;
	for (int i = 1; i <= n; ++i)fa1[i] =fa2[i]= i;
	for (int i = 1; i <= m1;++i) {
		int x, y;
		scanf("%d %d",&x,&y);
		f1[i][0] = x; f1[i][1] = y;
		if (find_fa1(x) != find_fa1(y))add_fa1(x,y),q1++;
	}
	for (int i = 1; i <= m2; ++i) {
		int x, y;
		scanf("%d %d", &x, &y);
		f2[i][0] = x; f2[i][1] = y;
		if (find_fa2(x) == find_fa2(y))continue;
		add_fa2(x, y); q2++; 
	}
	for (int i = 1; i <= n;++i) {
		for (int j = 1; j <= n;++j) {
			if (i == j)continue;
			if (find_fa1(i) == find_fa1(j)||find_fa2(i)==find_fa2(j))continue;
			ans[++tot][0] = i;
			ans[tot][1] = j;
			add_fa2(i, j); 
			add_fa1(i, j);
		}
	}
	printf("%d\n",tot);
	for (int i = 1; i <= tot;++i) {
		if(ans[i][0])printf("%d %d\n",ans[i][0],ans[i][1]);
	}
}

D2. Mocha and Diana (Hard Version)

题目大意:
题目相对于D1扩大了n的范围,到了1e5

思路:
先尽可能的去和一个点连接(这里用1节点),路径压缩。
然后我们去路径压缩后的并查集数组中找,这时每个集合的并查集数组的值都相同,去连接非1的集合,1的已经连过了

AC代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#define ll long long 
using namespace std;
const int maxn = 1e6+7;
int fa1[maxn], fa2[maxn];
int n, m1, m2;
void swap(int& x, int& y) { x ^= y ^= x ^= y; }
int find_fa1(int x) { return x == fa1[x] ? x : fa1[x] = find_fa1(fa1[x]); }
void add_fa1(int x,int y) {
	int u = find_fa1(x);
	int v = find_fa1(y);
	if (v < u)swap(v, u);
	fa1[v] = u;
}
int find_fa2(int x) { return x == fa2[x] ? x : fa2[x] = find_fa2(fa2[x]); }
void add_fa2(int x, int y) {
	int u = find_fa2(x);
	int v = find_fa2(y);
	if (v < u)swap(v,u);
	fa2[v] = u;
}
int tot;
int ans[maxn][2];
int mark1[maxn],mark2[maxn];
int main() {
	scanf("%d %d %d",&n,&m1,&m2);
	int q1 = 0,q2=0;
	for (int i = 1; i <= n; ++i)fa1[i] =fa2[i]= i;
	for (int i = 1; i <= m1;++i) {
		int x, y;
		scanf("%d %d",&x,&y);
		add_fa1(x, y);
	}
	for (int i = 1; i <= m2; ++i) {
		int x, y;
		scanf("%d %d", &x, &y);
		add_fa2(x, y);
	}
	for (int i = 2; i <= n;++i) {
		if (find_fa1(i) != 1 && find_fa2(i) != 1) {
			ans[++tot][0] = i;
			ans[tot][1] = 1;
			add_fa1(i, 1);
			add_fa2(i, 1);
		}
	}
	for (int i = 1,j=1; i <= n;++i) {//在第一个并查集中找非1的集合
		if (find_fa1(i) == 1 || mark1[find_fa1(i)])continue;
		while((find_fa2(j)==1||mark2[find_fa2(j)])&&j<=n)j++;//在第二个中找非1的集合
		if (j <= n)mark1[find_fa1(i)] = mark2[find_fa2(j)] = 1, ans[++tot][0] = i, ans[tot][1] = j;//连接两个集合
	}
	printf("%d\n",tot);
	for (int i = 1; i <= tot;++i) {
		if(ans[i][0])printf("%d %d\n",ans[i][0],ans[i][1]);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值