zoukankan      html  css  js  c++  java
  • 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 
    ");
    102         for(int i = 1; i <= K; i++) printf("%d ", imp[i]);
    103         puts("
    ");*/
    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 
    ", 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 
    ", 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 
    ", i, col[i]);
    198     }
    199     puts("");*/
    200     
    201     for(int x = 1; x <= n; x++) {
    202         //printf("x = %d 
    ", 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 
    ", x, y);
    206             if(!col[x] && !col[y]) {
    207                 g[1].add(x, y);
    208                 //printf("g1 : add %d %d 
    ", x, y);
    209             }
    210             else if(!col[x]) {
    211                 g[1].add(x, v[col[y]][0]);
    212                 //printf("g1 : add %d %d 
    ", 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 
    ", 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 
    ", v[col[x]][0], v[col[y]][0]);
    221             }
    222         }
    223     }
    224     
    225     g[1].DP(v[1][0], 0);
    226     
    227     printf("%d
    ", 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 : 
    ");
    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 : 
    ");
    252     //out(rt, g[2]);
    253     
    254     int ans = g[2].cal(rt);
    255     printf("%d
    ", 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 
    ", i, f[i], g[i]);
    34     }
    35     
    36     if(f[n] != -1) {
    37         printf("YES
    ");    
    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
    ");
    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
    ");
    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
    ", (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
    ", 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
    ", i + sum);
    58             return 0;
    59         }
    60     }
    61     
    62     return 0;
    63 }
    AC代码

    CF

  • 相关阅读:
    第一次作业-准备篇
    个人作业——软件工程实践总结&个人技术博客
    个人技术总结-spring boot编写接口和数据返回
    个人作业——软件评测
    结对第二次作业——某次疫情统计可视化的实现
    结对第一次—疫情统计可视化(原型设计)
    软工实践寒假作业(2/2)
    软工实践寒假作业(1/2)
    个人作业-软件工程实践总结
    Android实现多图选择
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10963845.html
Copyright © 2011-2022 走看看