A. Minimum Integer
签到。
![](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 ll l, r, d; 6 7 int main() 8 { 9 int t; scanf("%d", &t); 10 while (t--) 11 { 12 scanf("%lld%lld%lld", &l, &r, &d); 13 if (d < l) printf("%lld\n", d); 14 else printf("%lld\n", ((r / d) + 1) * d); 15 } 16 return 0; 17 }
B. Accordion
签到。
![](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 5000010 5 char s[N]; 6 7 int work() 8 { 9 int l = -1, r = -1, flag, len = strlen(s + 1); 10 flag = false; 11 for (int i = 1; i <= len; ++i) 12 { 13 if (s[i] == '[') flag = true; 14 else if (s[i] == ':' && flag) 15 { 16 l = i; 17 break; 18 } 19 } 20 if (l == -1) return -1; 21 flag = false; 22 for (int i = len; i >= 1; --i) 23 { 24 if (s[i] == ']') flag = true; 25 else if (s[i] == ':' && flag) 26 { 27 r = i; 28 break; 29 } 30 } 31 if (r == -1) return -1; 32 if (r <= l) return -1; 33 int res = 4; 34 for (int i = l + 1; i < r; ++i) if (s[i] == '|') 35 ++res; 36 return res; 37 } 38 39 int main() 40 { 41 while (scanf("%s", s + 1) != EOF) 42 printf("%d\n", work()); 43 return 0; 44 }
C. Division and Union
Solved.
题意:
有n个区间,将它分成两个集合,使得每个集合任意出一个区间组成的一对,这对没有交
思路:
按左端点排序,如果存在这样的划分,那么必定一个界限使得当前区间与之前的那个区间没有交,这样的话,后面的区间和之前的区间都不会有交
![](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 t, n, ans[N]; 6 struct node 7 { 8 int l, r, id; 9 void scan(int id) { scanf("%d%d", &l, &r); this->id = id; } 10 bool operator < (const node &other) const { return l < other.l || (l == other.l && r < other.r); } 11 }a[N]; 12 13 int main() 14 { 15 scanf("%d", &t); 16 while (t--) 17 { 18 scanf("%d", &n); 19 for (int i = 1; i <= n; ++i) a[i].scan(i); 20 sort(a + 1, a + 1 + n); 21 int pos = -1; int maxr = a[1].r; 22 for (int i = 2; i <= n; ++i) 23 { 24 if (a[i].l > maxr) 25 { 26 pos = i; 27 break; 28 } 29 maxr = max(maxr, a[i].r); 30 } 31 if (pos == -1) puts("-1"); 32 else 33 { 34 for (int i = 1; i <= n; ++i) ans[a[i].id] = i < pos ? 2 : 1; 35 for (int i = 1; i <= n; ++i) printf("%d%c", ans[i], " \n"[i == n]); 36 } 37 } 38 return 0; 39 }
D. GCD Counting
Upsolved.
题意:
一棵树中,每个点有权值,找出一条最长的简单路径,使得这个路劲上所有点的点权的gcd > 1
思路:
枚举质因子,再在虚树上dp
质因子很多,有1w多个,但是我们考虑每个质因子对应的集合的总和不会太多,
因为一个数的质因子个数不会太多,2e5一下也就十几个,那么一个数的贡献也就十几个
最后的总和就是O(nlogn)级别的
其实不用建虚树,直接在dfs序上dp就可以了
![](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 200010 5 int n, a[N], res; 6 vector <int> G[N]; 7 vector <int> fac[N]; 8 9 int fa[N], p[N], pos[N], cnt; int f[2][N]; 10 void pre(int u) 11 { 12 p[u] = ++cnt; 13 for (auto v : G[u]) if (v != fa[u]) 14 { 15 fa[v] = u; 16 pre(v); 17 } 18 } 19 20 void init() 21 { 22 for (int i = 1; i <= n; ++i) G[i].clear(); 23 for (int i = 2; i < N; ++i) fac[i].clear(); 24 memset(pos, -1, sizeof pos); 25 res = 0; cnt = 0; 26 } 27 28 int main() 29 { 30 while (scanf("%d", &n) != EOF) 31 { 32 init(); 33 for (int i = 1; i <= n; ++i) scanf("%d", a + i); 34 for (int i = 1, u, v; i < n; ++i) 35 { 36 scanf("%d%d", &u, &v); 37 G[u].push_back(v); 38 G[v].push_back(u); 39 } 40 pre(1); 41 for (int i = 1; i <= n; ++i) 42 { 43 int tmp = a[i]; 44 int limit = sqrt(tmp); 45 for (int j = 2; j <= limit; ++j) 46 { 47 if (tmp % j == 0) 48 { 49 fac[j].push_back(i); 50 while (tmp % j == 0) tmp /= j; 51 } 52 } 53 if (tmp != 1) fac[tmp].push_back(i); 54 } 55 for (int i = 2; i < N; ++i) if (fac[i].size() >= 1) 56 { 57 sort(fac[i].begin(), fac[i].end(), [](int x, int y) { return p[x] > p[y]; }); 58 int len = fac[i].size(); 59 for (int j = 0; j < len; ++j) for (int o = 0; o < 2; ++o) f[o][j] = 0; 60 for (int j = 0; j < len; ++j) pos[fac[i][j]] = j; 61 for (int j = 0, u, v; j < len; ++j) 62 { 63 v = fac[i][j]; 64 res = max(res, f[0][j] + f[1][j] + 1); 65 if (pos[fa[v]] != -1) 66 { 67 int id = pos[fa[v]]; 68 if (f[0][j] + 1 >= f[0][id]) 69 { 70 f[1][id] = f[0][id]; 71 f[0][id] = f[0][j] + 1; 72 } 73 else if (f[0][j] + 1 >= f[1][id]) 74 { 75 f[1][id] = f[0][j] + 1; 76 } 77 } 78 } 79 for (int j = 0; j < len; ++j) pos[fac[i][j]] = -1; 80 } 81 printf("%d\n", res); 82 } 83 return 0; 84 }
E. Polycarp's New Job
签到.
![](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 500010 5 int n, x, y, l, r; char op[10]; 6 7 int main() 8 { 9 l = 0, r = 0; 10 scanf("%d", &n); 11 while (n--) 12 { 13 scanf("%s%d%d", op, &x, &y); 14 if (x > y) swap(x, y); 15 if (op[0] == '+') 16 { 17 l = max(l, x); 18 r = max(r, y); 19 } 20 else 21 { 22 puts(l <= x && r <= y ? "YES" : "NO"); 23 } 24 } 25 return 0; 26 }
F. Trucks and Cities
Upsolved.
题意:
$有n个城市,有m辆卡车需要从s_i -> f_i 每公里耗油c_i升,最多加油r_i次$
$求最小的油箱体积,使得所有卡车都能在加油次数内到达目的地$
思路:
本来考虑二分$但是复杂度是O(n \cdot m \cdot log(10^{18}))$
考虑$dp$
$dp[i][j][k] 表示从i -> j 最多加油k次的最少油箱容量$
$dp[i][j][k] = \min_{w = i}^{j} max(dp[i][w][k - 1], a[j] - a[w])$
我们发现 $dp[i][w][k - 1] 随着w递增而增加,a[j] - a[w] 随着w递增而减少$
$但是,max(dp[i][w][k - 1], a[j] -a[w]) 是先减后增的$
并且随着$j的右移动,决策点肯定只会向右移动,而不会回到左边$
![](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 401 6 int n, m, a[N]; 7 int f[N][N][N]; 8 9 int main() 10 { 11 while (scanf("%d%d", &n, &m) != EOF) 12 { 13 for (int i = 1; i <= n; ++i) scanf("%d", a + i); 14 memset(f, 0, sizeof f); 15 for (int i = 1; i <= n; ++i) 16 for (int j = 1; j <= n; ++j) 17 f[i][j][0] = a[j] - a[i]; 18 for (int k = 1; k <= n; ++k) 19 for (int i = 1, w; i <= n; ++i) 20 { 21 w = i; 22 for (int j = i + 1; j <= n; ++j) 23 { 24 while (w < j && max(f[i][w + 1][k - 1], a[j] - a[w + 1]) <= max(f[i][w][k - 1], a[j] - a[w])) ++w; 25 f[i][j][k] = max(f[i][w][k - 1], a[j] - a[w]); 26 } 27 } 28 ll res = 0; 29 for (int i = 1, s, e, c, r; i <= m; ++i) 30 { 31 scanf("%d%d%d%d", &s, &e, &c, &r); 32 res = max(res, 1ll * c * f[s][e][r]); 33 } 34 printf("%lld\n", res); 35 } 36 return 0; 37 }
G. (Zero XOR Subset)-less
Upsolved.
题意:
将一些数分组,使得没有任意一个这些组的子集的异或和等于0
思路:
如果所有数异或起来等于$0$就是无解的情况
否则就是线性基中基的个数,因为每个基的最高位的$1所在位置不同$
$所以这些基不管怎么异或都不会是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 200010 5 int n, a[N], p[110]; 6 7 int main() 8 { 9 while (scanf("%d", &n) != EOF) 10 { 11 int t = 0; 12 for (int i = 1; i <= n; ++i) scanf("%d", a + i), t ^= a[i]; 13 if (!t) puts("-1"); 14 else 15 { 16 memset(p, 0, sizeof p); 17 for (int i = 1; i <= n; ++i) 18 for (int j = 31; j >= 0; --j) 19 if ((a[i] >> j) & 1) 20 { 21 if (!p[j]) 22 { 23 p[j] = a[i]; 24 break; 25 } 26 else a[i] ^= p[j]; 27 } 28 int res = 0; 29 for (int i = 0; i < 32; ++i) if (p[i]) ++res; 30 printf("%d\n", res); 31 } 32 } 33 return 0; 34 }