C. 4-adjacent
给定序列$a_i$,询问是否存在一个排列,满足$a_{p[i]}* a_{p[i + 1]}$是4的倍数
贪心构造
首先把只是2的倍数的数拿出来,放在最右边
前面把是1的倍数的数和是4的倍数的数交替放置即可
之后随意判断即可
#include <cstdio> #include <cstring> #include <iostream> using namespace std; extern inline char gc() { static char RR[23456], *S = RR + 23333, *T = RR + 23333; if(S == T) fread(RR, 1, 23333, stdin), S = RR; return *S ++; } inline int read() { int p = 0, w = 1; char c = gc(); while(c > '9' || c < '0') { if(c == '-') w = -1; c = gc(); } while(c >= '0' && c <= '9') p = p * 10 + c - '0', c = gc(); return p * w; } #define ri register int int n, n2, n4, flag; int main() { n = read(); for(ri i = 1; i <= n; i ++) { int x = read(); if(x % 4 == 0) n4 ++; else if(x % 2 == 0) n2 ++; } n -= n2; if(n & 1) { if(n2) flag = (n4 > n / 2); else flag = (n4 >= n / 2); } else flag = (n4 >= n / 2); if(flag) printf("Yes "); else printf("No "); return 0; }
D.Grid Coloring
对$R*W$的格子进行染色,需要使颜色$i$的出现次数为$c_i$
且同一颜色形成联通块,询问是否可行并给出一组方案
S形涂色即可
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define ri register int #define sid 105 int H, W, n, id; int col[sid][sid], ord[sid * sid]; int main() { scanf("%d%d%d", &H, &W, &n); for(ri i = 1; i <= n; i ++) { int x; scanf("%d", &x); while(x --) ord[++ id] = i; } id = 0; for(ri i = 1; i <= H; i ++) for(ri j = 1; j <= W; j ++) col[i][j] = ord[++ id]; for(ri i = 2; i <= H; i += 2) reverse(col[i] + 1, col[i] + W + 1); for(ri i = 1; i <= H; i ++, printf(" ")) for(ri j = 1; j <= W; j ++) printf("%d ", col[i][j]); return 0; }
E.Young Maids
题意略复杂,直接看原题面吧...
从前往后去贪心
每次选择的一定是某个区间中的奇(偶)最小值后其后的偶(奇)最小值
注意奇偶的判断即可
复杂度$O(n log n)$
一开始表示平衡树裸题,然后点开题解,还是打st表吧
#include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; extern inline char gc() { static char RR[23456], *S = RR + 23333, *T = RR + 23333; if(S == T) fread(RR, 1, 23333, stdin), S = RR; return *S ++; } inline int read() { int p = 0, w = 1; char c = gc(); while(c > '9' || c < '0') { if(c == '-') w = -1; c = gc(); } while(c >= '0' && c <= '9') p = p * 10 + c - '0', c = gc(); return p * w; } #define sid 200050 #define inf 1e9 #define ri register int int n; int bit[sid], l_g[sid]; int st[sid][21][2], v[sid][2], arc[sid]; void Init() { for(ri i = 0; i <= 30; i ++) bit[i] = 1 << i; for(ri i = 2; i <= n; i ++) l_g[i] = l_g[i >> 1] + 1; for(ri o = 0; o <= 1; o ++) for(ri i = 1; i <= n; i ++) st[i][0][o] = v[i][o]; for(ri o = 0; o <= 1; o ++) for(ri j = 1; bit[j] <= n; j ++) for(ri i = 1; i + bit[j] - 1 <= n; i ++) st[i][j][o] = min(st[i][j - 1][o], st[i + bit[j - 1]][j - 1][o]); } inline int rmq(int l, int r, int o) { int lg = l_g[r - l + 1]; return min(st[l][lg][o], st[r - bit[lg] + 1][lg][o]); } struct Seg { int v, l, r; friend bool operator < (Seg a, Seg b) { return a.v > b.v; } }; priority_queue <Seg> q; int main() { n = read(); for(ri i = 1; i <= n; i ++) { int w = (v[i][(i ^ 1) & 1] = read()); v[i][i & 1] = inf; arc[w] = i; } Init(); q.push({ rmq(1, n, 0), 1, n }); while(!q.empty()) { Seg tmp = q.top(); q.pop(); int w1 = tmp.v, pw1 = arc[w1]; int w2 = rmq(pw1 + 1, tmp.r, pw1 & 1), pw2 = arc[w2]; printf("%d %d ", w1, w2); if(tmp.l != pw1) q.push({ rmq(tmp.l, pw1 - 1, (tmp.l + 1) & 1), tmp.l, pw1 - 1 }); if(pw1 + 1 != pw2) q.push({ rmq(pw1 + 1, pw2 - 1, pw1 & 1), pw1 + 1, pw2 - 1 }); if(pw2 != tmp.r) q.push({ rmq(pw2 + 1, tmp.r, pw2 & 1), pw2 + 1, tmp.r }); } return 0; }
F.Prime Flip
有$n$个位置的牌向上,
每次可以选定一段长为$p$($p$为奇质数)的区间,翻转这个区间
询问最少几次能使所有牌向下
考虑构造新序列$e_i = [a_i = a_{i + 1}]$,$a_i$表示向上还是向下
当$e_i$全部为0时,原序列全部向下
那么,原题的区间操作转化为同时对两个点翻转
两个点匹配有3种情况
1.相差为奇质数,需要1次
2.相差为偶数,需要2次
3.否则,需要3次
对于第一种情况,做二分图匹配
第二种情况,讨论
第三种情况,讨论
对我而言是神题,不会做.....
然而有一堆AK的神仙....
#include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define ri register int #define ssd 10000010 #define sid 205 int n, N = 1e7; int pr[ssd / 10], tot; int nj, no, js[sid], os[sid]; bool nop[ssd], e[ssd]; int tim, vis[sid], mat[sid]; bool ex[sid][sid]; inline void Init() { nop[1] = 1; for(ri i = 2; i <= N + 1; i ++) { if(!nop[i]) pr[++ tot] = i; for(ri j = 1; j <= tot; j ++) { int nx = i * pr[j]; if(nx > N + 1) break; nop[nx] = 1; if(i % pr[j] == 0) break; } } nop[2] = 1; } inline int dfs(int o) { for(int i = 1; i <= no; i ++) if(ex[o][i] && vis[i] != tim) { vis[i] = tim; if(!mat[i] || dfs(mat[i])) return mat[i] = o, 1; } return 0; } int main() { Init(); cin >> n; for(ri i = 1; i <= n; i ++) { int x; cin >> x; e[x] = 1; } for(ri i = 1; i <= N + 1; i ++) if(e[i] != e[i - 1]) { if(i & 1) js[++ nj] = i; else os[++ no] = i; } for(ri i = 1; i <= nj; i ++) for(ri j = 1; j <= no; j ++) if(!nop[abs(js[i] - os[j])]) ex[i][j] = 1; int num = 0, ans = 0; for(ri i = 1; i <= nj; i ++) ++ tim, num += dfs(i); nj -= num; no -= num; ans = num + nj / 2 * 2 + no / 2 * 2 + (nj & 1) * 3; printf("%d ", ans); return 0; }