A Water The Garden
没啥好说的。
B Tea Queue
没啥好说的。
C Swap Adjacent Elements
题意大概就是给一个置换,有一些位置上是可以交换的,问能不能换成一个1 2 3 4 5...这样的置换。
好坑啊,一开始猜了个结论,以为对逆序产生贡献的地方有1就可以了。
5
1 5 2 3 4
0100
这一组就gg了。
实际上把连续出现1的那一部份都排个序,最后再check一下,复杂度想想是可以的。
![](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 const int N = 200005; 5 6 int n, a[N]; 7 char s[N]; 8 int main() { 9 scanf("%d", &n); 10 for (int i = 0; i < n; ++i) scanf("%d", a + i); 11 scanf("%s", s); 12 s[n - 1] = '0'; 13 14 int l, r; 15 l = r = -1; 16 for (int i = 0; i < n; ++i) { 17 int k = s[i] - '0'; 18 if (k) { 19 if (l != -1) r++; 20 else l = r = i; 21 } else { 22 if (l >= 0 && r >= 0) sort(a + l, a + r + 1 + 1); 23 l = r = -1; 24 } 25 } 26 bool flag = 1; 27 for (int i = 1; i < n; ++i) { 28 if (a[i] < a[i - 1]) { 29 flag = 0; break; 30 } 31 } 32 printf("%s", flag ? "YES" : "NO"); 33 }
D Tanks
没补。
E Connected Components?
题意大概是给你一个补图,问原图有多少个联通块,每个联通块里有几个结点。
有点类似于HDU5876。
不过这个题只要求联通块,那么每个点最多就被访问一次,存图还是得存补图的,用一个set或链表来维护当前有哪些点没有被访问过,BFS每次从这些没有被访问过的点里走原图中有边的点。
其实就是判断一下补图中是不是有边,补图中有边,那么原图就是没边的。
![](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 const int N = 2e5 + 7; 5 6 int n, m; 7 unordered_set<int> g[N]; 8 int vis[N]; 9 set<int> unused; 10 int main() { 11 scanf("%d %d", &n, &m); 12 for (int i = 0; i < m; ++i) { 13 int x, y; 14 scanf("%d %d", &x, &y); 15 g[x].insert(y); 16 g[y].insert(x); 17 } 18 for (int i = 1; i <= n; ++i) { 19 unused.insert(i); 20 } 21 22 vector<int> ans; 23 for (int i = 1; i <= n; ++i) { 24 if (!vis[i]) { 25 int cnt = 0; 26 queue<int> Q; 27 Q.push(i); unused.erase(i); 28 29 while (!Q.empty()) { 30 int u = Q.front(); 31 Q.pop(); 32 ++cnt; 33 vis[u] = true; 34 vector<int> del; 35 for (int v : unused) { 36 if (g[u].find(v) != g[u].end()) continue; 37 del.push_back(v); 38 Q.push(v); 39 } 40 for (int j : del) unused.erase(j); 41 } 42 ans.push_back(cnt); 43 } 44 } 45 46 sort(ans.begin(), ans.end()); 47 printf("%d\n", ans.size()); 48 for (int i : ans) printf("%d ", i); 49 printf("\n"); 50 }
F SUM and REPLACE
题意大概是有一个序列,每次操作一段区间,把这段区间里的每一个数都变成这个数的因子个数/查询这个区间的和。
有一个很好的性质就是,当这个数变成1或者2的时候这个数就不会变了。
线段树单点更新,区间查询咯。
那么搞搞就行了,因子也$sqrt(n)$的搞搞就好了,但是要维护一个区间最大值,当区间最大值 <= 2的时候就不需要搞下去了。
![](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 typedef long long ll; 5 #define lson o<<1 6 #define rson o<<1|1 7 const int N = 300030; 8 const int X = 1000001; 9 10 int n, m; 11 int a[N], d[X]; 12 struct node { 13 int l, r; 14 ll sum, max; 15 } st[N << 2]; 16 17 void init() { 18 for (int i = 1; i < X; ++i) 19 for (int j = i; j < X; j += i) d[j]++; 20 } 21 22 void push_up(int o) { 23 st[o].sum = st[lson].sum + st[rson].sum; 24 st[o].max = max(st[lson].max, st[rson].max); 25 } 26 27 void build(int l = 1, int r = n, int o = 1) { 28 st[o].l = l; st[o].r = r; st[o].sum = st[o].max = 0; 29 if (l == r) { 30 st[o].sum = st[o].max = a[l]; 31 return; 32 } 33 int mid = (l + r) / 2; 34 build(l, mid, lson); 35 build(mid + 1, r, rson); 36 push_up(o); 37 } 38 39 void advance(int l, int r, int o = 1) { 40 if (st[o].r < l or st[o].l > r or st[o].max <= 2) return; 41 if (st[o].l == st[o].r) { 42 st[o].sum = st[o].max = d[st[o].sum]; 43 return; 44 } 45 advance(l, r, lson); 46 advance(l, r, rson); 47 push_up(o); 48 } 49 50 ll query(int l, int r, int o = 1) { 51 if (st[o].r < l or st[o].l > r) return 0; 52 if (l <= st[o].l and st[o].r <= r) return st[o].sum; 53 return query(l, r, lson) + query(l, r, rson); 54 } 55 56 int main() { 57 init(); 58 scanf("%d %d", &n, &m); 59 for (int i = 1; i <= n; ++i) scanf("%d", a + i); 60 build(); 61 for (int i = 0; i < m; ++i) { 62 static int l, r, t; 63 scanf("%d %d %d", &t, &l, &r); 64 if (t == 1) { 65 advance(l, r); 66 } else { 67 printf("%lld\n", query(l, r)); 68 } 69 } 70 }
G List Of Integers
题意大概就是要求比x大的与p互质的第k个数。
没想到可以二分答案,那么问题就成了一个判定问题。
先搞出$[1, x]$中与p互质的数有几个(假设t个),再二分一下答案ans,判断一下$[1,ans]$中是不是大于等于t+k个,二分这个下界就是了。
算互质数个数的话,比较经典的问题,可以用容斥搞出与p不互质的数个数,减一减就好。
![](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 const int N = 1e6 + 20; 5 6 vector<int> a[N]; 7 vector<int> Q; 8 int t, x, p, k; 9 10 int solve(int n, int p) { 11 int ret = 0; 12 Q.clear(); 13 Q.push_back(-1); 14 vector<int> & f = a[p]; 15 for (int i = 0; i < (int)f.size(); ++i) { 16 int top = Q.size(); 17 for (int j = 0; j < top; ++j) { 18 Q.push_back(-1 * f[i] * Q[j]); 19 } 20 } 21 for (int i = 1; i < (int)Q.size(); ++i) { 22 ret += n / Q[i]; 23 } 24 return n - ret; 25 } 26 27 int main() { 28 for (int i = 2; i <= 1000000; ++i) { 29 if (a[i].size() > 0) continue; 30 for (int j = i; j <= 1000000; j += i) { 31 a[j].push_back(i); 32 } 33 } 34 35 scanf("%d", &t); 36 while (t--) { 37 scanf("%d %d %d", &x, &p, &k); 38 39 k += solve(x, p); 40 int lb = 1, ub = 1e9, ans = x; 41 while (lb <= ub) { 42 int mid = (lb + ub) / 2; 43 if (solve(mid, p) >= k) { 44 ans = mid; 45 ub = mid - 1; 46 } else { 47 lb = mid + 1; 48 } 49 } 50 printf("%d\n", ans); 51 } 52 }