5/5
失踪多天发一下CF的题解,突然发现CF题解评论区一堆大神在晒解法,我等渣渣就顺手膜拜了一发,学了不少姿势,以后一打完CF就去评论区找姿势好了。。。。。。
最近有一个感悟,就是不要让别人告诉你一道题的完整思路比较好,最后是懂得大致的解法,自己将所有实现细节都推导一遍,然后再看别人是怎么实现的,这样学到的更多,以前我都是看别人思路看别人的代码,然后发现自己的代码和别人的好像长得一样,原来我顺手把别人的代码copy到脑海中,这样印象不是很深刻,要自己推导实现一遍,然后在学习别人的代码和思路比较好。
题A A. Brain's Photos
题意:G、B、W输出“#Black&White”,否则输出“#Color”
题解:略
题B B. Bakery
题意:告诉你k个地方不能开面包店,然后剩下n-k个地方里面开,然后k个地方买面粉,问你有没有离卖面粉最短的距离开面包店。
题解:遍历卖面粉的,然后找一个非卖面粉的最短的即可,不行就输出-1。
题C C. Pythagorean Triples
题意:给你n,构造一个勾股数。
题解:另k^2 = n^2 + r^2 -> (k - r) * (k + r) = n ^ 2;
(1)n<=2,无解
(2)n为偶数
k - r = 2;
k + r = n ^ 2 / 2;
解得k = n ^ 2 / 4 + 1, r = n ^ 2 / 4 - 1;
(3)n为奇数
k - r = 1;
k + r = n ^ 2;
解得k = (n ^ 2 + 1) / 2, r = (n ^ 2 - 1) / 2;
题D D. Persistent Bookcase
题意:给你一个n * m的书架,有四种操作:
(1)1 i j,在(i,j)上放一本书;
(2)2 i j,拿掉(i,j)上的一本书;
(3)3 i,将第i行置反
(4)4 k,回到第k个操作
题解:有两种解法(还有一种主席树,本弱不太会):
(1)dfs离线,op = {1, 2, 3},i-1操作向i操作连边,op = {4},k操作向i操作连边,然后做操作即可,记得变回去。
1 /*zhen hao*/
2 #include <bits/stdc++.h>
3 using namespace std;
4
5 #define lson l, m, rt*2
6 #define rson m + 1, r, rt*2+1
7 #define X first
8 #define Y second
9
10 typedef pair<int,int> PII;
11 typedef long long LL;
12 typedef unsigned long long ULL;
13
14 const int N = 1e3 + 10, Q = 1e5 + 10;
15
16 struct Node {
17 int op, x, y;
18 } query[Q];
19
20 vector<int> g[Q];
21
22 int ans[Q], now;
23 bitset<N> bs[N], tmp;
24
25 void dfs(int k) {
26 int op = query[k].op, x = query[k].x, y = query[k].y, flag = 0;
27 if (op == 1) {
28 --x; --y;
29 if (bs[x][y] == 0) { flag = 1; now++; }
30 bs[x][y] = 1;
31 }
32 else if (op == 2) {
33 --x; --y;
34 if (bs[x][y] == 1) { flag = 1; now--; }
35 bs[x][y] = 0;
36 }
37 else if (op == 3) {
38 --x;
39 now -= bs[x].count();
40 bs[x] = bs[x] ^ tmp;
41 now += bs[x].count();
42 flag = 1;
43 }
44 // cout << k << ' ' << now << endl;
45 ans[k] = now;
46 for (int i = 0; i < (int)g[k].size(); i++) dfs(g[k][i]);
47 if (!flag) return;
48 if (op == 1) {
49 bs[x][y] = 0;
50 --now;
51 }
52 else if (op == 2) {
53 bs[x][y] = 1;
54 ++now;
55 }
56 else if (op == 3) {
57 now -= bs[x].count();
58 bs[x] = bs[x] ^ tmp;
59 now += bs[x].count();
60 }
61 }
62
63 int main() {
64 // freopen("case.in", "r", stdin);
65 int n, m, q;
66 cin >> n >> m >> q;
67 for (int i = 0; i < m; i++) tmp[i] = 1;
68 for (int i = 1; i <= q; i++) {
69 scanf("%d%d", &query[i].op, &query[i].x);
70 if (query[i].op < 3) scanf("%d", &query[i].y);
71 if (query[i].op == 4) g[query[i].x].push_back(i);
72 else g[i - 1].push_back(i);
73 }
74 dfs(0);
75 for (int i = 1; i <= q; i++) printf("%d
", ans[i]);
76 return 0;
77 }
(2)数组在线,观察到一共只有1e5种不同的行的形态,用一个biset来记录所有可能的状态,记得pos(i,j)表示第i个操作的每一行对应每一行在biset的编号,然后有新的行的形态产生就塞到biset即可,复杂度O(nq)。
1 /*zhen hao*/
2 #include <bits/stdc++.h>
3 using namespace std;
4
5 #define lson l, m, rt*2
6 #define rson m + 1, r, rt*2+1
7 #define X first
8 #define Y second
9
10 typedef pair<int,int> PII;
11 typedef long long LL;
12 typedef unsigned long long ULL;
13
14 const int N = 1e3 + 10, Q = 1e5 + 10;
15 bitset<N> bs[Q], tmp;
16 int pos[Q][N], res[Q];
17
18 int main() {
19 // freopen("case.in", "r", stdin);
20 int n, m, q, cnt = 0;
21 scanf("%d%d%d", &n, &m, &q);
22 for (int i = 1; i <= m; i++) tmp[i] = 1;
23 for (int i = 1; i <= q; i++) {
24 int op, x, y;
25 scanf("%d%d", &op, &x);
26 if (op == 4) {
27 for (int j = 1; j <= n; j++) pos[i][j] = pos[x][j];
28 res[i] = res[x];
29 }
30 else {
31 for (int j = 1; j <= n; j++) pos[i][j] = pos[i - 1][j];
32 res[i] = res[i - 1];
33 int id = pos[i][x];
34 if (op == 1) {
35 scanf("%d", &y);
36 if (bs[id][y] == 1) { printf("%d
", res[i]); continue; }
37 bs[++cnt] = bs[id];
38 bs[cnt][y] = 1;
39 res[i]++;
40 pos[i][x] = cnt;
41 }
42 if (op == 2) {
43 scanf("%d", &y);
44 if (bs[id][y] == 0) { printf("%d
", res[i]); continue; }
45 bs[++cnt] = bs[id];
46 bs[cnt][y] = 0;
47 res[i]--;
48 pos[i][x] = cnt;
49 }
50 if (op == 3) {
51 bs[++cnt] = bs[id];
52 res[i] -= bs[cnt].count();
53 bs[cnt] = bs[cnt] ^ tmp;
54 res[i] += bs[cnt].count();
55 pos[i][x] = cnt;
56 }
57 }
58 printf("%d
", res[i]);
59 }
60 return 0;
61 }
题E E. Garlands
题意:在n * m的网格上,给你k条链,一开始默认开,然后有两种操作(1)询问子矩阵的权值和,统计其中开的链的权值和,(2)将一条链置反。
题解:感觉离线做比较好,虽说在线也不会超时。
先将每一个ask操作(最多2000)记录下来,然后对于每个链维护一个res[i][j]表示i链在第j个ask里面的权值和,然后询问就可以做到O(k)。
1 /*zhen hao*/
2 #include <bits/stdc++.h>
3 using namespace std;
4
5 #define lson l, m, rt*2
6 #define rson m + 1, r, rt*2+1
7 #define X first
8 #define Y second
9
10 typedef pair<int,int> PII;
11 typedef long long LL;
12 typedef unsigned long long ULL;
13
14 const int N = 2100, Q = 1e6 + 10;
15
16 struct BIT {
17 int n, m;
18 LL C[N][N];
19 inline int lowbit(int x) {
20 return x & (-x);
21 }
22 void update(int x, int y, int d) {
23 for (int i = x; i <= n; i += lowbit(i))
24 for (int j = y; j <= m; j += lowbit(j))
25 C[i][j] += d;
26 }
27 LL sum(int x, int y) {
28 LL ret = 0;
29 for (int i = x; i; i -= lowbit(i))
30 for (int j = y; j; j -= lowbit(j))
31 ret += C[i][j];
32 return ret;
33 }
34 } T;
35
36 struct Ask {
37 int x1, y1, x2, y2;
38 } A[N];
39
40 struct Node {
41 int x, y, z;
42 };
43
44 vector<Node> link[N];
45 char s[Q][10];
46 int sw[Q], flag[Q];
47 LL ans[N][N];
48
49 int main() {
50 // freopen("case.in", "r", stdin);
51 int n, m, k, q;
52 cin >> n >> m >> k;
53 T.n = n;
54 T.m = m;
55 for (int i = 0; i < k; i++) {
56 int sz, x, y, z;
57 scanf("%d", &sz);
58 while (sz--) {
59 scanf("%d%d%d", &x, &y, &z);
60 link[i].push_back((Node){x, y, z});
61 }
62 }
63 scanf("%d", &q);
64 int cnt = 0;
65 for (int i = 0; i < q; i++) {
66 scanf("%s", s[i]);
67 if (s[i][0] == 'A') {
68 scanf("%d%d%d%d", &A[cnt].x1, &A[cnt].y1, &A[cnt].x2, &A[cnt].y2);
69 cnt++;
70 }
71 else {
72 scanf("%d", sw + i);
73 sw[i]--;
74 }
75 }
76 for (int i = 0; i < k; i++) {
77 for (int j = 0; j < (int)link[i].size(); j++) T.update(link[i][j].x, link[i][j].y, link[i][j].z);
78 for (int j = 0; j < cnt; j++)
79 ans[i][j] = T.sum(A[j].x2, A[j].y2) + T.sum(A[j].x1 - 1, A[j].y1 - 1) - T.sum(A[j].x1 - 1, A[j].y2) - T.sum(A[j].x2, A[j].y1 - 1);
80 for (int j = 0; j < (int)link[i].size(); j++) T.update(link[i][j].x, link[i][j].y, -link[i][j].z);
81 }
82 cnt = 0;
83 for (int i = 0; i < k; i++) flag[i] = 1;
84 for (int i = 0; i < q; i++) {
85 if (s[i][0] == 'A') {
86 LL res = 0;
87 for (int j = 0; j < k; j++) if (flag[j]) res += ans[j][cnt];
88 printf("%I64d
", res);
89 cnt++;
90 }
91 else {
92 flag[sw[i]] ^= 1;
93 }
94 }
95 return 0;
96 }