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 \n", 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 \n", 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 \n", 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\n", 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 \n", 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\n", 1ll * ans * (MO + 1) / 2 % MO);
145     return 0;
146 }
50分代码

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

猜你喜欢

转载自www.cnblogs.com/huyufeifei/p/10742757.html