A Mocha and Math
题目
给定一个长度为 n n n 的数列 a a a,每次可以选择一个区间 [ l , r ] [l,r] [l,r],对于 0 ≤ i ≤ r − l 0\le i\le r-l 0≤i≤r−l,将 a l + i a_{l+i} al+i 变为 a l + i and a r − i a_{l+i}\ \operatorname{and}\ a_{r-i} al+i and ar−i。其中 and \operatorname{and} and 表示按位与。
你可以进行无限多次操作,问最终序列中最大值最小是多少。
思路
按为与的结果是不会增的,所以我们能操作就操作,根据题目意思,每两个数之间都可以进行按位与操作,因此,答案就是所有数按为与的结果.
代码
#include <iostream>
#include <cstdio>
using namespace std;
int read() {
int re = 0;
char c = getchar();
bool negt = false;
while(c < '0' || c > '9')
negt |= (c == '-') , c = getchar();
while(c >= '0' && c <= '9')
re = (re << 1) + (re << 3) + c - '0' , c = getchar();
return negt ? -re : re;
}
template <char l , char r>
char readc() {
char c = getchar();
while(c < l || c > r)c = getchar();
return c;
}
const int N = 110;
int a[N];
int n;
int ans = 0;
void solve() {
n = read();
ans = (unsigned)(-1);
for(int i = 1 ; i <= n ; i++)
ans &= read();
cout << ans << endl;
}
int main() {
int T = read();
while(T--)solve();
return 0;
}
B B Mocha and Red and Blue
题目
给定长为 n n n 的仅由 R \texttt{R} R、 B \texttt{B} B、 ? \texttt{?} ? 组成的字符串 S S S,请你在 ? \texttt{?} ? 处填入 R \texttt{R} R 或 B \texttt{B} B,使得相邻位置字符相同的数量最少。
思路
本来还在想奇奇怪怪的DP,然后发现贪心就好.
对于每个位置
i
∈
[
2
,
n
]
i\in[2,n]
i∈[2,n],如果前面是B
我们就放R
,前面是R
,我们就放B
.这样每个位置最多只可能和右边冲突.
对于第一个位置,如果是?
,我们找到从左向右第一个不是?
的位置,和那个位置错开即可.
代码
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int read() {
int re = 0;
char c = getchar();
bool negt = false;
while(c < '0' || c > '9')
negt |= (c == '-') , c = getchar();
while(c >= '0' && c <= '9')
re = (re << 1) + (re << 3) + c - '0' , c = getchar();
return negt ? -re : re;
}
char readc() {
char c = getchar();
while(c != 'R' && c != 'G' && c != 'B' && c != '?')c = getchar();
return c;
}
const int N = 110;
char s[N];
int n;
int f[N][5];
const char col[] = "RB";
void solve() {
memset(s , 0 , sizeof(s));
n =read();
int pos = 0;
for(int i = 1 ; i <= n ; i++) {
// char c = readc();
s[i] = readc();
if(pos == 0 && s[i] != '?')pos = i;
}
if(pos != 0 && s[1] == '?')s[1] = "BR"[(pos % 2 + (s[pos] == 'B') ) % 2];
for(int i = 1 ; i <= n ; i++)
if(s[i] == '?') {
s[i] = s[i - 1] == 'B' ? 'R' : 'B';
}
puts(s + 1);
}
int main() {
int T = read();
while(T--)solve();
return 0;
}
C Mocha and Hiking
题目
给定一张 n n n 个点 2 n − 1 2n-1 2n−1 条边的图,其中边分两种:
- 对于所有 1 ≤ i ≤ n 1\le i\le n 1≤i≤n,存在一条由节点 i i i 连向节点 i + 1 i+1 i+1 的边;
- 对于所有 1 ≤ i ≤ n 1\le i\le n 1≤i≤n,存在一条由节点 i i i 连向节点 n + 1 n+1 n+1 的边或者一条由节点 n + 1 n+1 n+1 连向节点 i i i 的边。
请你输出一种从任意一个点开始遍历所有点的方案,若无法遍历则输出 − 1 -1 −1。
思路
由题目我们可以看到,总体趋势是向右走的,且需要额外考虑的是 n + 1 n+1 n+1号点.
- 如果 a 1 = 1 a_1=1 a1=1,走以下路径: n + 1 → 1 → 2 → ⋯ → n n+1\to1\to2\to\cdots\to n n+1→1→2→⋯→n.
- 如果 a n = 0 a_n=0 an=0,走以下路径: 1 → 2 → 3 → 4 → ⋯ → n → n + 1 1\to2\to3\to4\to\cdots\to n\to n+1 1→2→3→4→⋯→n→n+1.
- 如果存在一个 i i i, a i = 0 , a i + 1 = 1 a_i=0,a_{i+1}=1 ai=0,ai+1=1走以下路径: 1 → 2 → 3 → ⋯ → i → n + 1 → i + 1 → i + 2 → ⋯ → n 1\to2\to3\to\cdots\to i\to n+1\to i+1\to i+2\to\cdots\to n 1→2→3→⋯→i→n+1→i+1→i+2→⋯→n.
以上包含了所有有解的情况.
代码
#include <iostream>
#include <cstdio>
using namespace std;
int read() {
int re = 0;
char c = getchar();
bool negt = false;
while(c < '0' || c > '9')
negt |= (c == '-') , c = getchar();
while(c >= '0' && c <= '9')
re = (re << 1) + (re << 3) + c - '0' , c = getchar();
return negt ? -re : re;
}
template <char l , char r>
char readc() {
char c = getchar();
while(c < l || c > r)c = getchar();
return c;
}
const int N = 1e4 + 10;
int a[N];
void solve() {
int n;
n = read();
for(int i = 1 ; i <= n ; i++)a[i] = read();
for(int i = 1 ; i < n ; i++) {
if(a[i] == 0 && a[i + 1] == 1) {
for(int j = 1 ; j <= i ; j++)
printf("%d " , j);
printf ("%d " , n + 1);
for(int j = i + 1 ; j <= n ; j++)
printf("%d " , j);
putchar('\n');
return ;
}
}
if(a[1] == 1) {
printf("%d " , n + 1);
for(int i = 1 ; i <= n ; i++)
printf ("%d " , i);
putchar('\n');
return ;
}
if(a[n] == 0) {
for(int i = 1 ; i <= n + 1 ; i++)
printf("%d " , i);
putchar('\n');
return ;
}
puts("-1");
}
int main() {
int T = read();
while(T--)solve();
return 0;
}
D1&D2 Mocha and Diana
题目
给你两棵森林,节点数均为 n n n。
允许你进行加边操作,但是有两个要求:
- 如果在第一个森林加一条 ( u , v ) (u,v) (u,v) 的边,第二个森林也要进行同样的操作。反之同理。
- 加边后两个森林依旧是森林。(一棵树也是森林)
求最多能加几条边,并输出加边方案。
思路
对于D1,枚举两个点 u , v u,v u,v能连就连,连玩合并并查集即可,时间复杂度为 O ( n 2 ) O(n^2) O(n2).
对于D2,我们分两步:
- 从枚举一个点 u u u, 1 , u 1,u 1,u两个点能连就连,连玩放入一个并查集.这样我们在两个森林中分别得到两个大连通块,为了方便,成为连通块A,和连通块B.
- 枚举连通块A外的一个点
u
u
u,和连通块B外的一个点
v
v
v.
u
,
v
u,v
u,v是一定可以连边的.
简单证明就是 u u u一定在连通块B中(如果不在,第一步就会将 u , v u,v u,v连起来), v v v也一定在连通块A中(同理).
因此, u , v u,v u,v满足连边条件.所以将 u , v u,v u,v连边,然后它们就都同时在A,B连通块内了,(所以一个点只能用一次).我们求出所有不在A连通块内的点的集合,和所有不在B连通块内的点的集合,两个集合内的点互相连边即可(可以证明两个集合的交集为空).
代码
#include <iostream>
#include <cstdio>
#include <vector>
#include <map>
using namespace std;
int read() {
int re = 0;
char c = getchar();
bool negt = false;
while(c < '0' || c > '9')
negt |= (c == '-') , c = getchar();
while(c >= '0' && c <= '9')
re = (re << 1) + (re << 3) + c - '0' , c = getchar();
return negt ? -re : re;
}
template <char l , char r>
char readc() {
char c = getchar();
while(c < l || c > r)c = getchar();
return c;
}
const int N = 1e5 + 10;
int n;
int m1 , m2;
vector <pair<int , int> > ans;
struct DSU {
int fa[N];
DSU() {
for(int i = 0 ; i < N ; i++)fa[i] = i;
}
int findroot(int x) {
return fa[x] == x ? x : (fa[x] = findroot(fa[x]));
}
void merge(int u , int v) {
u = findroot(u) , v = findroot(v);
if(u != v)
fa[u] = v;
}
} d1 , d2;
int main() {
n = read() , m1 = read() , m2 = read();
for(int i = 1 ; i <= m1 ; i++) {
int u = read() , v = read();
d1.merge(u , v);
}
for(int i = 1 ; i <= m2 ; i++) {
int u = read() , v = read();
d2.merge(u , v);
}
for(int i = 2 ; i <= n ; i++) {
if(d1.findroot(1) != d1.findroot(i) && d2.findroot(1) != d2.findroot(i)) {
d1.merge(1 , i) , d2.merge(1 , i);
ans.push_back(make_pair(1 , i));
}
}
vector <int> a , b;
for(int i = 1 ; i <= n ; i++) {
if(d1.findroot(1) != d1.findroot(i))a.push_back(i) , d1.merge(1 , i);
else if(d2.findroot(1) != d2.findroot(i))b.push_back(i) , d2.merge(1 , i);
}
for(int i = 0 ; i < a.size() && i < b.size() ; i++)
ans.push_back(make_pair(a[i] , b[i]));
printf("%d\n" , ans.size());
for(auto i : ans) {
printf("%d %d\n" , i.first , i.second);
}
return 0;
}