A. Parity
签.
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 100010 5 int b, k, a[N]; 6 7 int main() 8 { 9 while (scanf("%d%d", &b, &k) != EOF) 10 { 11 int res = 0; 12 for (int i = 1; i <= k; ++i) scanf("%d", a + i); 13 int base = 1; 14 for (int i = k; i >= 1; --i) 15 { 16 res = (res + a[i] * base % 2) % 2; 17 base = base * b % 2; 18 } 19 puts(res % 2 ? "odd" : "even"); 20 } 21 return 0; 22 }
做的时候卡了一会儿
因为想用费马小定理
认为
$b^x = b^{(x \% \phi(m))} \pmod m$
然后幂次都变为$0$
就直接加起来$模2判断一下就好了$
$但是没有考虑到0^0次的问题$
$在这里如果b \% 2 == 0, 那么带b的项都为0$
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 100010 5 int b, k, a[N]; 6 7 int main() 8 { 9 while (scanf("%d%d", &b, &k) != EOF) 10 { 11 int res = 0; 12 for (int i = 1; i <= k; ++i) scanf("%d", a + i); 13 for (int i = 1; i <= k; ++i) 14 res = (res + a[i] % 2) % 2; 15 if (b % 2 == 0) res = a[k]; 16 puts(res % 2 ? "odd" : "even"); 17 } 18 return 0; 19 }
B. Tape
签.
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 100010 5 int n, m, k; 6 int b[N]; 7 8 int main() 9 { 10 while (scanf("%d%d%d", &n, &m, &k) != EOF) 11 { 12 --k; 13 for (int i = 1; i <= n; ++i) scanf("%d", b + i); 14 int res = b[n] - b[1] + 1; 15 priority_queue <int> pq; 16 for (int i = 2; i <= n; ++i) pq.push(b[i] - b[i - 1] - 1); 17 while (!pq.empty() && k--) 18 { 19 res -= pq.top(); 20 pq.pop(); 21 } 22 printf("%d\n", res); 23 } 24 return 0; 25 }
C. Meaningless Operations
Solved.
题意:
给出一个数$a$
$定义(f(a) = max_{1 <= b < a} gcd(a \oplus b, a \& b))$
给出$f(a)$
思路:
考虑$gcd(x, 0) = x$
那么我们构造$(a \& b) = 0, 并且 (a \oplus b)最大即可$
$对于2^x - 1 这种东西是没法构造的$
$考虑这样的数不多,提前打表即可$
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int q, x; 5 map <int, int> ans; 6 7 int solve(int x) 8 { 9 if (ans.find(x) != ans.end()) return ans[x]; 10 int res; 11 for (int i = 24; i >= 0; --i) if (((x >> i) & 1)) 12 { 13 res = (1 << (i + 1)) - 1; 14 break; 15 } 16 return ans[x] = res; 17 } 18 19 int main() 20 { 21 ans[1] = 1, 22 ans[3] = 1, 23 ans[7] = 1, 24 ans[15] = 5, 25 ans[31] = 1, 26 ans[63] = 21, 27 ans[127] = 1, 28 ans[255] = 85, 29 ans[511] = 73, 30 ans[1023] = 341, 31 ans[2047] = 89, 32 ans[4095] = 1365, 33 ans[8191] = 1, 34 ans[16383] = 5461, 35 ans[32767] = 4681, 36 ans[65535] = 21845, 37 ans[131071] = 1, 38 ans[262143] = 87381, 39 ans[524287] = 1, 40 ans[1048575] = 349525, 41 ans[2097151] = 299593, 42 ans[4194303] = 1398101, 43 ans[8388607] = 178481, 44 ans[16777215] = 5592405, 45 ans[33554431] = 1082401; 46 while (scanf("%d", &q) != EOF) 47 { 48 while (q--) 49 { 50 scanf("%d", &x); 51 printf("%d\n", solve(x)); 52 } 53 } 54 return 0; 55 }
D. Jongmah
Upsolved.
题意:
有一些数字,三个相同的数字消去
三个连续的也可以消去
求最多消去多少组
思路:
$dp[i][j][k] 表示到第i大的数, 第i - 2大的数还余了j个, 第i - 1个数还余了k个$
$的最大消去的组数$
$转移的时候注意能跟前面的余数组成连续的就组成连续的$
$因为和前面余数组成连续的只需要出一张牌就获得1的贡献$
$如果消去当前三张相同的需要三张牌,至少是不会亏的$
$注意转移的时候要把前面的余数也剪掉$
$再考虑每张牌最多出5张和前面和后面的其他牌组成连续的$
$那么j, k的状态只有6个$
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 5 #define ll long long 6 #define N 1000010 7 int n, m, a[N]; 8 ll f[2][6][6]; 9 10 int main() 11 { 12 while (scanf("%d%d", &n, &m) != EOF) 13 { 14 memset(a, 0, sizeof a); 15 memset(f, -1, sizeof f); 16 for (int i = 1, x; i <= n; ++i) 17 { 18 scanf("%d", &x); 19 ++a[x]; 20 } 21 if (m <= 2) 22 { 23 printf("%d\n", a[1] / 3 + a[2] / 3); 24 continue; 25 } 26 ll res = 0; 27 for (int i = 0; i < 6; ++i) 28 for (int j = 0; j < 6; ++j) 29 if (a[1] >= i && a[2] >= j) 30 f[2 & 1][i][j] = (a[1] - i) / 3 + (a[2] - j) / 3; 31 //for (int i = 1; i <= m; ++i) printf("%d%c", a[i], " \n"[i == m]); 32 for (int i = 3; i <= m; ++i) 33 { 34 for (int j = 0; j < 6; ++j) 35 for (int k = 0; k < 6; ++k) 36 f[i & 1][j][k] = -1; 37 for (int j = 0; j < 6; ++j) 38 { 39 for (int k = 0; k < 6; ++k) if (f[(i & 1) ^ 1][j][k] != -1) 40 { 41 for (int o = 0; o < 6; ++o) 42 { 43 int need = min(j, min(a[i] - o, k)); 44 ll base = f[(i & 1) ^ 1][j][k]; 45 if (a[i] >= o) 46 f[i & 1][k - need][o] = max(f[i & 1][k - need][o], base + (a[i] - o - need) / 3 + need); 47 } 48 } 49 } 50 //for (int j = 0; j < 3; ++j) 51 // for (int k = 0; k < 3; ++k) 52 // printf("%d %d %d %lld\n", i, j, k, f[i][j][k]); 53 } 54 for (int i = 0; i < 6; ++i) 55 for (int j = 0; j < 6; ++j) 56 res = max(res, f[m & 1][i][j]); 57 printf("%lld\n", res); 58 } 59 return 0; 60 }
E. Magic Stones
Upsolved.
题意:
有一个数字序列$A[], 每次可以选择一个i \in [2, n - 1]$
$使得 A[i] = A[i + 1] + A[i - 1] - A[i]$
问能否经过一些这样的操作,使得$A[] -> B[]$
思路:
我们令$d[i] = A[i + 1] - A[i]$
我们考虑$上述的那个操作$
$d_i = A[i + 1] - (A[i + 1] + A[i - 1] - A[i]) = A[i] - A[i - 1] = d_{i - 1}$
同理
$d_{i - 1} = d_{i}$
我们注意到,这个操作变成了交换元素
$那么把B[]数组也变成差分数组,如果两个差分数组通过任意交换后相同$
$那么原序列通过以系列操作也可以相同$
$即排个序判断是否相同即可,再注意一下第一个是否相同$
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 100010 5 int n, c[N], t[N]; 6 int a[N], b[N]; 7 8 bool ok() 9 { 10 for (int i = 1; i < n; ++i) 11 if (a[i] != b[i]) 12 return false; 13 return true; 14 } 15 16 int main() 17 { 18 while (scanf("%d", &n) != EOF) 19 { 20 for (int i = 1; i <= n; ++i) 21 { 22 scanf("%d", c + i); 23 if (i > 1) 24 a[i - 1] = c[i] - c[i - 1]; 25 } 26 for (int i = 1; i <= n; ++i) 27 { 28 scanf("%d", t + i); 29 if (i > 1) 30 b[i - 1] = t[i] - t[i - 1]; 31 } 32 sort(a + 1, a + n); 33 sort(b + 1, b + n); 34 puts(ok() && c[1] == t[1] ? "Yes" : "No"); 35 } 36 return 0; 37 }
F. Nearest Leaf
Upsolved.
题意:
给出一个树, 询问$离v节点最近叶子节点的距离$
注意给出的点序是$DFS序$
思路:
将询问离线,令根为$1$
$考虑如果询问1号点,那么跑一遍DFS,将所有点的距离丢进线段树$
$查最小值即可$
那么对于一个点$x$
我们考虑从线段树里面维护的距离是到它父亲$y的距离$
$那么我们要把这个距离转变成到x的距离$
$可以发现,它子树内的点都需要减去一条边,就是它父亲到它那条边$
$它子树外的点都需要加上一条边,是它父亲到它那条边$
$子树内的点是连续的,所以可以在线段树上操作$
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 #define N 500010 6 int n, q; 7 struct qnode 8 { 9 int l, r, id; 10 qnode () {} 11 qnode (int l, int r, int id) : l(l), r(r), id(id) {} 12 }; 13 vector <qnode> vec[N]; 14 ll ans[N]; 15 struct Graph 16 { 17 struct node 18 { 19 int to, nx, w; 20 node () {} 21 node (int to, int nx, int w) : to(to), nx(nx), w(w) {} 22 }a[N << 1]; 23 int head[N], pos; 24 void init() 25 { 26 memset(head, 0, sizeof head); 27 pos = 0; 28 } 29 void add(int u, int v, int w) 30 { 31 a[++pos] = node(v, head[u], w); head[u] = pos; 32 a[++pos] = node(u, head[v], w); head[v] = pos; 33 } 34 }G; 35 #define erp(u) for (int it = G.head[u], v = G.a[it].to, w = G.a[it].w; it; it = G.a[it].nx, v = G.a[it].to, w = G.a[it].w) 36 int fa[N], isleaf[N]; ll dis[N]; 37 38 namespace SEG 39 { 40 ll Min[N << 2], lazy[N << 2]; 41 void pushup(int id) { Min[id] = min(Min[id << 1], Min[id << 1 | 1]); } 42 void build(int id, int l, int r) 43 { 44 lazy[id] = 0; 45 if (l == r) 46 { 47 Min[id] = dis[l]; 48 if (!isleaf[l]) Min[id] = (ll)1e18; 49 return; 50 } 51 int mid = (l + r) >> 1; 52 build(id << 1, l, mid); 53 build(id << 1 | 1, mid + 1, r); 54 pushup(id); 55 } 56 void pushdown(int id) 57 { 58 if (!lazy[id]) return; 59 lazy[id << 1] += lazy[id]; 60 lazy[id << 1 | 1] += lazy[id]; 61 Min[id << 1] += lazy[id]; 62 Min[id << 1 | 1] += lazy[id]; 63 lazy[id] = 0; 64 } 65 void update(int id, int l, int r, int ql, int qr, ll val) 66 { 67 if (l >= ql && r <= qr) 68 { 69 Min[id] += val; 70 lazy[id] += val; 71 return; 72 } 73 pushdown(id); 74 int mid = (l + r) >> 1; 75 if (ql <= mid) update(id << 1, l, mid, ql, qr, val); 76 if (qr > mid) update(id << 1 | 1, mid + 1, r, ql, qr, val); 77 pushup(id); 78 } 79 ll query(int id, int l, int r, int ql, int qr) 80 { 81 if (l >= ql && r <= qr) return Min[id]; 82 pushdown(id); 83 int mid = (l + r) >> 1; 84 ll res = (ll)1e18; 85 if (ql <= mid) res = min(res, query(id << 1, l, mid, ql, qr)); 86 if (qr > mid) res = min(res, query(id << 1 | 1, mid + 1, r, ql, qr)); 87 return res; 88 } 89 } 90 91 int lp[N], rp[N]; 92 void DFS1(int u) 93 { 94 lp[u] = u; 95 rp[u] = u; 96 erp(u) if (v != fa[u]) 97 { 98 fa[v] = u; 99 dis[v] = dis[u] + w; 100 DFS1(v); 101 rp[u] = max(rp[u], rp[v]); 102 } 103 isleaf[u] = (lp[u] == rp[u]); 104 } 105 106 void DFS2(int u) 107 { 108 for (auto it : vec[u]) 109 ans[it.id] = SEG::query(1, 1, n, it.l, it.r); 110 erp(u) if (v != fa[u]) 111 { 112 SEG::update(1, 1, n, 1, n, w); 113 SEG::update(1, 1, n, lp[v], rp[v], -2ll * w); 114 DFS2(v); 115 SEG::update(1, 1, n, 1, n, -w); 116 SEG::update(1, 1, n, lp[v], rp[v], 2ll * w); 117 } 118 } 119 120 int main() 121 { 122 while (scanf("%d%d", &n, &q) != EOF) 123 { 124 for (int i = 1; i <= n; ++i) vec[i].clear(); 125 G.init(); 126 for (int i = 2, p, w; i <= n; ++i) 127 { 128 scanf("%d%d", &p, &w); 129 G.add(i, p, w); 130 } 131 for (int i = 1, v, l, r; i <= q; ++i) 132 { 133 scanf("%d%d%d", &v, &l, &r); 134 vec[v].emplace_back(l, r, i); 135 } 136 dis[1] = 0; 137 DFS1(1); 138 SEG::build(1, 1, n); 139 DFS2(1); 140 for (int i = 1; i <= q; ++i) printf("%lld\n", ans[i]); 141 } 142 return 0; 143 }