[题目链接]
https://codeforces.com/contest/1326/problem/F2
[题解]
首先因为有 (0) 和 (1) 两种关系不好处理。 考虑容斥 , 记 (ans(s)) 表示至少有 (s) 的方案数。 最后就只需要做一个逆高维前缀和就能求出 (f(s)) 了。
考虑设 (f_{s , i}) 表示集合 (s) 组成一条最后一个节点为 (i) 的方案数。 (g_{s}) 表示集合 (s) 组成一条链的方案数。 (f) 可以用简单的状压动态规划求得。 而 (g_{s}) 就是 (sum{f_{s , i}})。
那么有 (ans_{s} = sum{prod_{g_{t_{i}}}}) , 其中 (t_{i}) 表示每个连续段由哪些点组成。 满足 (t_{1} igcup t_{2} igcup .... t_{m} = U) ((U) 为全集)。
直接枚举 (t) 不可行 , 一个重要性质是 : 对于组成情况相同的两个串 (s1) , (s2) , 有 (ans(s1) = ans(s2))。
(18) 的拆分数为 (385) , 并不大 , 于是直接枚举串的组成情况 , 设长度大小关系 (|t_{1}| leq |t_{2}| leq |t_{3}| .... leq |t_{m}|) , 在枚举的时候将 (FMT) 得到的点值乘起来 , 最后 (IFMT) 回去 , 其对这样组成情况的串的贡献就是第 (2 ^ {n} - 1) 次项的系数。 具体实现的时候可以不 (IFMT) , 直接根据现实意义容斥即可。
时间复杂度 : (O(2 ^ {N} ho(n))) 的。
[代码]
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MN = 20;
#define all(a) (a).begin() , (a).end()
int N;
char s[MN];
int bitcnt[1 << MN];
LL ans[1 << MN] , g[MN][1 << MN] , f[MN][1 << MN];
map < vector < int > , vector < int > > qs;
vector < int > E[MN];
inline void inc(LL &x , LL y) {
x += y;
}
inline void dec(LL &x , LL y) {
x -= y;
}
inline void dfs(int r , const std::vector<int> &l, const std::vector<LL> &s) {
if (!r) {
LL res = 0; int msk = (1 << N) - 1;
for (int i = 0; i < (1 << N); ++i)
if (bitcnt[msk ^ i] & 1) dec(res , s[i]);
else inc(res , s[i]);
for (int o : qs[l]) inc(ans[o] , res);
return;
}
int lst = l.empty() ? 1 : l.back();
for (int k = lst; k <= r; ++k) {
if (k < r && r - k < k) continue;
vector < LL > ns(s); vector < int > nl(l);
nl.emplace_back(k);
for (int i = 0; i < (1 << N); ++i) ns[i] *= g[k - 1][i];
dfs(r - k , nl , ns);
}
}
int main() {
scanf("%d" , &N);
for (int i = 0; i < N; ++i) {
scanf("%s" , s);
for (int j = 0; j < N; ++j)
if (s[j] == '1') E[i].emplace_back(j);
}
bitcnt[0] = 0;
for (int i = 1; i < (1 << N); ++i) bitcnt[i] = bitcnt[i >> 1] + (i & 1);
for (int i = 0; i < N; ++i) f[i][1 << i] = 1;
for (int S = 1; S < (1 << N); ++S)
for (int i = 0; i < N; ++i)
if (f[i][S]) {
inc(g[bitcnt[S] - 1][S] , f[i][S]);
for (int v : E[i]) if ((S >> v & 1) == 0) inc(f[v][S | (1 << v)] , f[i][S]);
}
for (int k = 0; k < N; ++k)
for (int i = 0; i < N; ++i)
for (int S = 0; S < (1 << N); ++S)
if (S >> i & 1) inc(g[k][S] , g[k][S ^ (1 << i)]);
for (int S = 0; S < (1 << (N - 1)); ++S) {
vector < int > a; int x = 1;
for (int i = 0; i < N - 1; ++i)
if (S >> i & 1) ++x;
else a.emplace_back(x) , x = 1;
a.emplace_back(x); sort(all(a));
qs[a].emplace_back(S);
}
dfs(N , vector < int > () , vector< LL > (1 << N , 1));
for (int i = 0; i < N - 1; ++i)
for (int S = 0; S < (1 << (N - 1)); ++S)
if (S >> i & 1) dec(ans[S ^ (1 << i)] , ans[S]);
for (int S = 0; S < (1 << (N - 1)); ++S) printf("%lld " , ans[S]);
printf("
");
return 0;
}