[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} 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;
}
原文地址:https://www.cnblogs.com/evenbao/p/14029547.html