[CF1326F] Wise Men (Hard Version)

[题目链接]

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} \bigcup t_{2} \bigcup .... 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}\rho(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("\n");
	return 0;
}
posted @ 2020-11-24 12:11  evenbao  阅读(118)  评论(0编辑  收藏  举报