zoukankan      html  css  js  c++  java
  • [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;
    }
  • 相关阅读:
    烂泥:mysql修改本地主机连接
    烂泥:ESXI开启SNMP服务
    烂泥:【解决】VMware Workstation中安装ESXI5.0双网卡问题
    JS-日历签到
    CSS-文本(中,英)
    js-无缝向上滚动
    js-键盘回车搜索enter
    小程序-初次进入小程序的授权问题(授权更新后的完整步骤)button主动授权
    字蛛(font-spider)-单独压缩字体(解决页面少有的特殊字体的字体包引用)
    js-利用插件qrcode.min.js,前端实时生成二维码
  • 原文地址:https://www.cnblogs.com/evenbao/p/14029547.html
Copyright © 2011-2022 走看看