Codeforces Round #738 Div. 2
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]);
}
}