Codeforces Round #368 (Div. 2)

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\n", 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\n", 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\n", 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\n", 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\n", res);
89       cnt++;
90     }
91     else {
92       flag[sw[i]] ^= 1;
93     }
94   }
95   return 0;
96 }
代码君

 

posted @ 2016-08-22 20:03  zhenhao'Blog  阅读(174)  评论(0编辑  收藏  举报