CF集萃3

CF1118F2 - Tree Cutting

题意:给你一棵树,每个点被染成了k种颜色之一或者没有颜色。你要切断恰k - 1条边使得不存在两个异色点在同一连通块内。求方案数。

解:对每颜色构建最小斯坦纳树并判交。我用的树上差分实现。

然后把同一颜色的点缩成一个点,在新树上树形DP,fx表示x子树内,x所在连通块内有一个关键点的方案数。hx表示x所在连通块内没有关键点的方案数。

  1 #include <bits/stdc++.h>
  2 
  3 const int N = 300010, MO = 998244353;
  4 
  5 struct Edge {
  6     int nex, v, len;
  7 };
  8 
  9 int n, m, col[N], pw[N << 1], fr[N], imp[N], K, stk[N], top, f[N], h[N];
 10 std::vector<int> v[N];
 11 
 12 inline void ERR() {
 13     puts("0");
 14     exit(0);
 15     return;
 16 }
 17 
 18 struct G {
 19     Edge edge[N << 1]; int tp;
 20     int e[N], d[N], fa[N], pos[N], num, ST[N << 1][20];
 21     G(){}
 22     inline void add(int x, int y, int z = 0) {
 23         edge[++tp].v = y;
 24         edge[tp].len = z;
 25         edge[tp].nex = e[x];
 26         e[x] = tp;
 27         return;
 28     }
 29     void DFS_1(int x, int f) {
 30         d[x] = d[f] + 1;
 31         fa[x] = f;
 32         pos[x] = ++num;
 33         ST[num][0] = x;
 34         for(int i = e[x]; i; i = edge[i].nex) {
 35             int y = edge[i].v;
 36             if(y == f) continue;
 37             DFS_1(y, x);
 38             ST[++num][0] = x;
 39         }
 40         return;
 41     }
 42     inline void pre1(int x = 1) {
 43         DFS_1(x, 0);
 44         return;
 45     }
 46     inline void lcapre() {
 47         for(int j = 1; j <= pw[num]; j++) {
 48             for(int i = 1; i + (1 << j) - 1 <= num; i++) {
 49                 if(d[ST[i][j - 1]] < d[ST[i + (1 << (j - 1))][j - 1]]) {
 50                     ST[i][j] = ST[i][j - 1];
 51                 }
 52                 else {
 53                     ST[i][j] = ST[i + (1 << (j - 1))][j - 1];
 54                 }
 55             }
 56         }
 57         return;
 58     }
 59     inline int lca(int x, int y) {
 60         x = pos[x];
 61         y = pos[y];
 62         if(x > y) std::swap(x, y);
 63         int t = pw[y - x + 1];
 64         if(d[ST[x][t]] < d[ST[y - (1 << t) + 1][t]]) {
 65             return ST[x][t];
 66         }
 67         else {
 68             return ST[y - (1 << t) + 1][t];
 69         }
 70     }
 71     int recol(int x) {
 72         int Col = 0;
 73         for(int i = e[x]; i; i = edge[i].nex) {
 74             int y = edge[i].v;
 75             if(y == fa[x]) {
 76                 continue;
 77             }
 78             int c = recol(y);
 79             if(c && Col && c != Col) {
 80                 ERR();
 81             }
 82             if(c && !Col) {
 83                 Col = c;
 84             }
 85         }
 86         if(col[x]) {
 87             if(Col && col[x] != Col) {
 88                 ERR();
 89             }
 90             else {
 91                 Col = col[x];
 92             }
 93         }
 94         col[x] = Col;
 95         if(fr[x]) {
 96             Col = 0;
 97         }
 98         return Col;
 99     }
100     inline int build_t(G &gr) {
101         /*printf("build virtue tree \n");
102         for(int i = 1; i <= K; i++) printf("%d ", imp[i]);
103         puts("\n");*/
104         
105         stk[top = 1] = imp[1];
106         for(int i = 2; i <= K; i++) {
107             int x = imp[i], y = lca(x, stk[top]);
108             while(top > 1 && pos[y] <= pos[stk[top - 1]]) {
109                 gr.add(stk[top - 1], stk[top], d[stk[top]] - d[stk[top - 1]]);
110                 top--;
111             }
112             if(y != stk[top]) {
113                 gr.add(y, stk[top], d[stk[top]] - d[y]);
114                 stk[top] = y;
115             }
116             stk[++top] = x;
117         }
118         while(top > 1) {
119             gr.add(stk[top - 1], stk[top], d[stk[top]] - d[stk[top - 1]]);
120             top--;
121         }
122         return stk[top];
123     }
124     int cal(int x) {
125         int ans = 1;
126         for(int i = e[x]; i; i = edge[i].nex) {
127             int y = edge[i].v;
128             int t = cal(y);
129             ans = 1ll * ans * t % MO * edge[i].len % MO;
130         }
131         return ans;
132     }
133     void DP(int x, int father) {
134         f[x] = col[x] ? 1 : 0;
135         h[x] = col[x] ? 0 : 1;
136         for(int i = e[x]; i; i = edge[i].nex) {
137             int y = edge[i].v;
138             if(y == father) continue;
139             DP(y, x);
140             /// 
141             int t, t2;
142             t = 1ll * f[x] * (f[y] + h[y]) % MO + 1ll * f[y] * h[x] % MO;
143             t2 = 1ll * h[x] * (h[y] + f[y]) % MO;
144             f[x] = t % MO;
145             h[x] = t2;
146         }
147         //printf("x = %d f[x] = %d h[x] = %d \n", x, f[x], h[x]);
148         return;
149     }
150 }g[3];
151 
152 inline bool cmp(const int &a, const int &b) {
153     return g[1].pos[a] < g[1].pos[b];
154 }
155 
156 void out(int x, G &gr) {
157     for(int i = gr.e[x]; i; i = gr.edge[i].nex) {
158         int y = gr.edge[i].v;
159         if(y == gr.fa[x]) continue;
160         //printf("%d -> %d len = %d \n", x, y, gr.edge[i].len);
161         out(y, gr);
162     }
163     return;
164 }
165 
166 int main() {
167     
168     scanf("%d%d", &n, &m);
169     for(int i = 2; i <= n * 2; i++) pw[i] = pw[i >> 1] + 1;
170     for(int i = 1; i <= n; i++) {
171         scanf("%d", &col[i]);
172         if(col[i]) {
173             v[col[i]].push_back(i);
174         }
175     }
176 
177     for(int i = 1; i < n; i++) {
178         int x, y;
179         scanf("%d%d", &x, &y);
180         g[0].add(x, y);
181         g[0].add(y, x);
182     }
183     g[0].pre1();
184     g[0].lcapre();
185     for(int i = 1; i <= m; i++) {
186         //std::sort(v[i].begin(), v[i].end());
187         int len = v[i].size(), x = v[i][0];
188         for(int j = 1; j < len; j++) {
189             x = g[0].lca(x, v[i][j]);
190         }
191         fr[x] = i;
192     }
193     
194     g[0].recol(1);
195     
196     /*for(int i = 1; i <= n; i++) {
197         printf("i = %d col = %d \n", i, col[i]);
198     }
199     puts("");*/
200     
201     for(int x = 1; x <= n; x++) {
202         //printf("x = %d \n", x);
203         for(int i = g[0].e[x]; i; i = g[0].edge[i].nex) {
204             int y = g[0].edge[i].v;
205             //printf("%d -> %d \n", x, y);
206             if(!col[x] && !col[y]) {
207                 g[1].add(x, y);
208                 //printf("g1 : add %d %d \n", x, y);
209             }
210             else if(!col[x]) {
211                 g[1].add(x, v[col[y]][0]);
212                 //printf("g1 : add %d %d \n", x, v[col[y]][0]);
213             }
214             else if(!col[y]) {
215                 g[1].add(v[col[x]][0], y);
216                 //printf("g1 : add %d %d \n", v[col[x]][0], y);
217             }
218             else if(col[x] != col[y]) {
219                 g[1].add(v[col[x]][0], v[col[y]][0]);
220                 //printf("g1 : add %d %d \n", v[col[x]][0], v[col[y]][0]);
221             }
222         }
223     }
224     
225     g[1].DP(v[1][0], 0);
226     
227     printf("%d\n", f[v[1][0]]);
228     return 0;
229     
230     
231     
232     g[1].pre1(v[1][0]);
233     g[1].lcapre();
234     
235     /*printf("out G1 : \n");
236     out(v[1][0], g[1]);
237     puts("");*/
238     
239     for(int i = 1; i <= m; i++) {
240         imp[++K] = v[i][0];
241     }
242     /*for(int i = 1; i <= n; i++) {
243         if(!col[i]) {
244             imp[++K] = i;
245         }
246     }*/
247     
248     std::sort(imp + 1, imp + K + 1, cmp);
249     int rt = g[1].build_t(g[2]);
250     
251     //printf("out G2 : \n");
252     //out(rt, g[2]);
253     
254     int ans = g[2].cal(rt);
255     printf("%d\n", ans);
256     return 0;
257 }
AC代码

代码中有一些冗余部分....

CF1144G - Two Merged Sequences

题意:给你一个序列,你要把它拆成一个单增和一个单减序列。n <= 200000, 空间256M。

解:我一开始想到了一个2-sat + 主席树优化连边的做法,但是因为过高的空间复杂度导致MLE/RE.....

正解是DP,我们可以设fi表示第i个元素在上升序列中,下降序列的结尾最大值。gi反之。有4种转移。

 1 #include <bits/stdc++.h>
 2 
 3 const int N = 200010;
 4 
 5 int a[N], f[N], g[N], fr[N], gr[N], vis[N];
 6 
 7 int main() {
 8     int n;
 9     scanf("%d", &n);
10     for(int i = 1; i <= n; i++) {
11         scanf("%d", &a[i]);
12     }
13     memset(g, 0x3f, sizeof(g));
14     memset(f, -1, sizeof(f));
15     f[1] = N, g[1] = -1;
16     for(int i = 2; i <= n; i++) {
17         if(a[i - 1] < a[i] && f[i] <= f[i - 1]) {
18             f[i] = f[i - 1];
19             fr[i] = 1;
20         }
21         if(g[i - 1] < a[i] && f[i] <= a[i - 1]) {
22             f[i] = a[i - 1];
23             fr[i] = 2;
24         }
25         if(a[i - 1] > a[i] && g[i] >= g[i - 1]) {
26             g[i] = g[i - 1];
27             gr[i] = 2;
28         }
29         if(f[i - 1] > a[i] && g[i] >= a[i - 1]) {
30             g[i] = a[i - 1];
31             gr[i] = 1;
32         }
33         //printf("i = %d f = %d g = %d \n", i, f[i], g[i]);
34     }
35     
36     if(f[n] != -1) {
37         printf("YES\n");    
38         int t = 1;
39         for(int i = n; i >= 1; i--) {
40             vis[i] = t;
41             if(t == 1) t = fr[i];
42             else t = gr[i];
43         }
44         for(int i = 1; i <= n; i++) {
45             printf("%d ", vis[i] - 1);
46         }
47         return 0;
48     }
49     if(g[n] != 0x3f3f3f3f) {
50         printf("YES\n");
51         int t = 2;
52         for(int i = n; i >= 1; i--) {
53             vis[i] = t;
54             if(t == 1) t = fr[i];
55             else t = gr[i];
56         }
57         for(int i = 1; i <= n; i++) {
58             printf("%d ", vis[i] - 1);
59         }
60         return 0;
61     }
62     printf("NO\n");
63     return 0;
64 }
AC代码
  1 #include <bits/stdc++.h>
  2 
  3 const int N = 6000010, lm = 200001;
  4 
  5 struct Edge {
  6     int nex, v;
  7 }edge[N]; int tp;
  8 
  9 int n, tot, e[N], ls[N], rs[N], dfn[N], low[N], num, a[200010], rt[200010], rt2[200010], rt3[200010], rt4[200010];
 10 int fr[N], scc_cnt;
 11 std::stack<int> S;
 12 
 13 inline void add(int x, int y) {
 14     edge[++tp].v = y;
 15     edge[tp].nex = e[x];
 16     e[x] = tp;
 17     return;
 18 }
 19 
 20 void tarjan(int x) {
 21     low[x] = dfn[x] = ++num;
 22     S.push(x);
 23     for(int i = e[x]; i; i = edge[i].nex) {
 24         int y = edge[i].v;
 25         if(!dfn[y]) {
 26             tarjan(y);
 27             low[x] = std::min(low[x], low[y]);
 28         }
 29         else if(!fr[y]) {
 30             low[x] = std::min(low[x], dfn[y]);
 31         }
 32     }
 33     if(low[x] == dfn[x]) {
 34         int y;
 35         ++scc_cnt;
 36         do {
 37             y = S.top();
 38             S.pop();
 39             fr[y] = scc_cnt;
 40         } while(x != y);
 41     }
 42     return;
 43 }
 44 
 45 void insert(int &x, int y, int p, int id, int l, int r) {
 46     if(!x || x == y) {
 47         x = ++tot;
 48         ls[x] = ls[y];
 49         rs[x] = rs[y];
 50     }
 51     if(l == r) {
 52         add(x, id);
 53         if(y) add(x, y);
 54         return;
 55     }
 56     int mid = (l + r) >> 1;
 57     if(p <= mid) {
 58         insert(ls[x], ls[y], p, id, l, mid);
 59     }
 60     else {
 61         insert(rs[x], rs[y], p, id, mid + 1, r);
 62     }
 63     if(ls[x]) {
 64         add(x, ls[x]);
 65     }
 66     if(rs[x]) {
 67         add(x, rs[x]);
 68     }
 69     return;
 70 }
 71 
 72 void Add(int id, int L, int R, int l, int r, int o) {
 73     if(!o) return;
 74     if(L <= l && r <= R) {
 75         add(id, o);
 76         return;
 77     }
 78     int mid = (l + r) >> 1;
 79     if(L <= mid) {
 80         Add(id, L, R, l, mid, ls[o]);
 81     }
 82     if(mid < R) {
 83         Add(id, L, R, mid + 1, r, rs[o]);
 84     }
 85     return;
 86 }
 87 
 88 int main() {
 89     printf("%d\n", (sizeof(e) * 8 + sizeof(a) * 5) / 1048576);
 90     scanf("%d", &n);
 91     for(int i = 1; i <= n; i++) {
 92         scanf("%d", &a[i]);
 93         a[i]++;
 94     }
 95     
 96     /// build 
 97     tot = n * 2;
 98     for(int i = 1; i <= n; i++) {
 99         if(i < n) {
100             insert(rt[i], rt[i - 1], a[i], i + n, 1, lm);
101         }
102         if(i > 1) {
103             Add(i, a[i], lm, 1, lm, rt[i - 1]);
104         }
105     }
106     
107     for(int i = 1; i <= n; i++) {
108         if(i < n) {
109             insert(rt2[i], rt2[i - 1], a[i], i, 1, lm);
110         }
111         if(i > 1) {
112             Add(i + n, 1, a[i], 1, lm, rt2[i - 1]);
113         }
114     }
115     
116     for(int i = n; i >= 1; i--) {
117         if(i > 1) {
118             insert(rt3[i], rt3[i + 1], a[i], i + n, 1, lm);
119         }
120         if(i < n) {
121             Add(i, 1, a[i], 1, lm, rt3[i + 1]);
122         }
123     }
124     
125     for(int i = n; i >= 1; i--) {
126         if(i > 1) {
127             insert(rt4[i], rt4[i + 1], a[i], i, 1, lm);
128         }
129         if(i < n) {
130             Add(i + n, a[i], lm, 1, lm, rt4[i + 1]);
131         }
132     }
133     
134     for(int i = 1; i <= tot; i++) {
135         if(!dfn[i]) {
136             tarjan(i);
137         }
138     }
139     
140     for(int i = 1; i <= n; i++) {
141         if(fr[i] == fr[i + n]) {
142             puts("NO");
143             return 0;
144         }
145     }
146     puts("YES");
147     for(int i = 1; i <= n; i++) {
148         if(fr[i] < fr[i + n]) {
149             printf("0 ");
150         }
151         else {
152             printf("1 ");
153         }
154     }
155     puts("");
156     return 0;
157 }
2-sat代码,仅供参考,不保证正确

CF1132E Knapsack

题意:给定8e16个物体,每个物体的体积在1 ~ 8中。求不超过W体积的情况下最接近W能得到多少体积。

解:考虑到答案要么是sum,要么不会小于W - 7,,而且由于物品体积都非常小所以随便调整几下就能得到解。

于是先贪心到W - 8以上,然后用bitset做正反两个背包,然后枚举答案判定即可。

 1 #include <bits/stdc++.h>
 2 
 3 typedef long long LL;
 4 
 5 const int N = 10010;
 6 
 7 std::bitset<N> f, g, h;
 8 LL W, a[10], b[10];
 9 
10 int main() {
11     LL sum = 0;
12     scanf("%lld", &W);
13     for(int i = 1; i <= 8; i++) {
14         scanf("%lld", &a[i]);
15         sum += a[i] * i;
16     }
17     if(sum <= W) {
18         printf("%lld\n", sum);
19         return 0;
20     }
21     
22     sum = 0;
23     for(int i = 1; i <= 8; i++) {
24         if(sum + a[i] * i <= W) {
25             sum += a[i] * i;
26             std::swap(a[i], b[i]);
27         }
28         else {
29             LL cnt = (W - sum) / i;
30             sum += cnt * i;
31             b[i] = cnt;
32             a[i] -= cnt;
33             break;
34         }
35     }
36     
37     f.set(0);
38     g.set(0);
39     for(int i = 1; i <= 8; i++) {
40         int lm = std::min(a[i], 100ll);
41         for(int j = 1; j <= lm; j++) {
42             f |= f << i;
43         }
44     }
45     for(int i = 1; i <= 8; i++) {
46         int lm = std::min(b[i], 100ll);
47         for(int j = 1; j <= lm; j++) {
48             g |= g << i;
49         }
50     }
51     
52     int delta = W - sum;
53     for(int i = delta; i >= 0; i--) {
54         /// check if f-g = i
55         h = (g << i) & f;
56         if(h.any()) {
57             printf("%lld\n", i + sum);
58             return 0;
59         }
60     }
61     
62     return 0;
63 }
AC代码

CF

posted @ 2019-06-02 18:42  huyufeifei  阅读(237)  评论(0编辑  收藏  举报
试着放一个广告栏(虽然没有一分钱广告费)

『Flyable Heart 応援中!』 HHG 高苗京铃 闪十PSS 双六 電動伝奇堂 章鱼罐头制作组 はきか 祝姬 星降夜