LOJ#2723 多邊形

解:首先,n<=20的直接暴力建圖而後狀壓哈密頓迴路,相信你們都會。固定1爲起點,fi,s表示結尾爲i點,狀態爲s。每次遍歷i的出邊轉移,最後遍歷1的出邊統計答案。n22nc++

而後就是正經題解了。先考慮K = 1的時候。對於一個子樹,咱們發現它只有三個地方有出邊,左右上。而除此以外內部怎麼連是不要緊的,只要知足每一個點都通過就好了。ide

因而就設fi,j表示以i爲根的子樹中,與外界連通狀態爲j的方案數。0表示從左右出去且通過根節點,1表示從左上出去,2表示從右上出去,3表示從左右出去且不通過根節點(這是爲了方便轉移才設的)。spa

每次合併兩個子樹而非一次作整個根節點(方便以後K > 1的時候),因而咱們考慮每一個狀態如何被轉移來:code

  • 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的轉移。blog

而後輸出f[1][0]便可得到30分,配合暴力有50分。 it

  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的部分:event

相關文章
相關標籤/搜索