zoukankan      html  css  js  c++  java
  • LOJ#2723 多边形

    解:首先,n<=20的直接暴力建图然后状压哈密顿回路,相信大家都会。固定1为起点,fi,s表示结尾为i点,状态为s。每次遍历i的出边转移,最后遍历1的出边统计答案。n22n

    然后就是正经题解了。先考虑K = 1的时候。对于一个子树,我们发现它只有三个地方有出边,左右上。而除此之外内部怎么连是没关系的,只要满足每个点都经过就行了。

    于是就设fi,j表示以i为根的子树中,与外界连通状态为j的方案数。0表示从左右出去且经过根节点,1表示从左上出去,2表示从右上出去,3表示从左右出去且不经过根节点(这是为了方便转移才设的)。

    每次合并两个子树而非一次做整个根节点(方便之后K > 1的时候),于是我们考虑每个状态如何被转移来:

    • 0由所有子树中某两个相邻的12状态和两边的0状态转移来。也就是从0 + 0(前面有两个相邻的12)或1 + 2转移来。
    • 1由最后的一个1和前面的所有0转移过来。也就是3 + 1。
    • 2由最前面的一个2和后面的所有0转移过来,也就是2 + 0,注意要特判当前子树为第一个子树时的情况。
    • 3由所有0转移过来,也就是0 + 0。

    于是我们得到了一个O(n)的树形DP,注意根节点最后一个子树合并上来的时候,状态0还有一种情况就是最左2 + 中间0 + 最右1也就是2 + 1的转移。

    然后输出f[1][0]即可获得30分,配合暴力有50分。

      1 #include <bits/stdc++.h>
      2 
      3 const int N = 1010, MO = 998244353;
      4 
      5 struct Edge {
      6     int nex, v;
      7 }edge[N << 1]; int tp;
      8 
      9 int e[N], n, K, fa[N], stk[N], top, pw[1200000];
     10 int f[22][1200000];
     11 std::vector<int> G[N];
     12 std::bitset<N> bt[N];
     13 
     14 inline void add(int x, int y) {
     15     tp++;
     16     //printf("add %d %d 
    ", x, y);
     17     bt[x].set(y);
     18     edge[tp].v = y;
     19     edge[tp].nex = e[x];
     20     e[x] = tp;
     21     return;
     22 }
     23 
     24 void DFS(int x) {
     25     if(!G[x].size()) {
     26         stk[++top] = x;
     27     }
     28     for(int i = 0; i < (int)G[x].size(); i++) {
     29         int y = G[x][i];
     30         DFS(y);
     31     }
     32     return;
     33 }
     34 
     35 inline void link(int x, int y) {
     36     if(bt[x][y]) {
     37         return;
     38     }
     39     add(x, y);
     40     add(y, x);
     41     return;
     42 }
     43 
     44 inline void out(int x) {
     45     for(int i = 0; i < n; i++) {
     46         printf("%d", (x >> i) & 1);
     47     }
     48     return;
     49 }
     50 
     51 namespace k1 {
     52     int f[N][4];
     53     void DFS(int x) {
     54         if(!G[x].size()) {
     55             f[x][0] = f[x][1] = f[x][2] = 1;
     56             //printf("x = %d  %d %d %d %d 
    ", x, f[x][0], f[x][1], f[x][2], f[x][3]);
     57             return;
     58         }
     59         f[x][3] = 1;
     60         for(int i = 0; i < G[x].size(); i++) {
     61             int y = G[x][i];
     62             DFS(y);
     63             ///merge
     64             int t0 = (1ll * f[x][0] * f[y][0] % MO + 1ll * f[x][1] * f[y][2] % MO) % MO;
     65             int t1 = 1ll * f[x][3] * f[y][1] % MO;
     66             int t2 = i ? 1ll * f[x][2] * f[y][0] % MO : f[y][2];
     67             int t3 = 1ll * f[x][3] * f[y][0] % MO;
     68             if(x == 1 && i == G[x].size() - 1) {
     69                 (t0 += 1ll * f[x][2] * f[y][1] % MO) %= MO;
     70             }
     71             f[x][0] = t0;
     72             f[x][1] = t1;
     73             f[x][2] = t2;
     74             f[x][3] = t3;
     75         }
     76         //printf("x = %d  %d %d %d %d 
    ", x, f[x][0], f[x][1], f[x][2], f[x][3]);
     77         return;
     78     }
     79     inline void solve() {
     80         DFS(1);
     81         printf("%d
    ", f[1][0]);
     82         return;
     83     }
     84 }
     85 
     86 int main() {
     87 
     88     //freopen("polygon.in", "r", stdin);
     89     //freopen("polygon.out", "w", stdout);
     90 
     91     scanf("%d%d", &n, &K);
     92 
     93     for(int i = 2, x; i <= n; i++) {
     94         scanf("%d", &x);
     95         add(x, i); add(i, x);
     96         fa[i] = x;
     97         G[x].push_back(i);
     98     }
     99 
    100     for(int i = 1; i <= n; i++) std::sort(G[i].begin(), G[i].end());
    101 
    102     if(K == 1) {
    103         k1::solve();
    104         return 0;
    105     }
    106 
    107     DFS(1);
    108 
    109     for(int i = 1; i <= top; i++) {
    110         for(int j = 1; j <= K; j++) {
    111             int temp = i + j;
    112             if(temp > top) {
    113                 temp %= top;
    114             }
    115             if(!temp) {
    116                 temp = top;
    117             }
    118             link(stk[i], stk[temp]);
    119         }
    120     }
    121 
    122     int lm = (1 << n);
    123     for(int i = 2; i <= lm; i++) pw[i] = pw[i >> 1] + 1;
    124     f[1][1] = 1;
    125     for(int s = 1; s < lm; s++) {
    126         for(int x = 1; x <= n; x++) {
    127             /// f[x][s]
    128             if(!f[x][s]) continue;
    129             //printf("f %d ", x); out(s); printf(" = %d 
    ", f[x][s]);
    130             for(int i = e[x]; i; i = edge[i].nex) {
    131                 int y = edge[i].v;
    132                 if((s >> (y - 1)) & 1) {
    133                     continue;
    134                 }
    135                 (f[y][s | (1 << (y - 1))] += f[x][s]) %= MO;
    136             }
    137         }
    138     }
    139     int ans = 0;
    140     for(int i = e[1]; i; i = edge[i].nex) {
    141         int y = edge[i].v;
    142         ans = (ans + f[y][lm - 1]) % MO;
    143     }
    144     printf("%lld
    ", 1ll * ans * (MO + 1) / 2 % MO);
    145     return 0;
    146 }
    50分代码

    接下来说说K > 1的部分:

  • 相关阅读:
    HDFS数据流——读数据流程
    HDFS网络拓扑概念及机架感知(副本节点选择)
    HDFS数据流——写数据流程
    HDFS基本概念
    Hadoop运行模式:本地模式、伪分布模式、完全分布模式
    Java枚举enum关键字
    Java内部类
    Eclipse常用快捷键
    Linux中Mysql安装卸载
    服务器同时运行两个项目
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10742757.html
Copyright © 2011-2022 走看看