Codeforces 1326F Wise Men (容斥原理、状压 DP、划分数)
题目链接
F1: https://codeforces.com/contest/1326/problem/F1
F2: https://codeforces.com/contest/1326/problem/F2
题解
好题。
考虑容斥,对每个 01
串求满足串中为 \(1\) 的位置必须为 \(1\)、串中为 \(0\) 的位置 \(0\) 或 \(1\) 均可的排列的个数。最后把超集和还原回来即可。
这样的好处是,本质不同的状态只有拆分数 \(P(n)\) 个,即一个状态的答案只和所有连续的 \(1\) 的长度构成的可重集合有关。于是考虑 DFS 枚举划分数。
先预处理 \(f_S\) 表示 \(S\) 点集内有多少条哈密尔顿回路经过的边全是 \(1\).
对于一个状态,假设每一段的长度是 \(a_1,a_2,...,a_l\). 那么就相当于我们要找 \(l\) 个状态 \(s_1,S_2,...,s_l\), 满足 \(\forall i, \text{bitcnt}(s_i)=a_i\) 且 \(\text{or}^l_{i=1}s_i=2^n-1\),贡献为 \(\prod^l_{i=1}f_{s_i}\). 写成集合幂级数的形式,设 \(g_i\) 是一个集合幂级数,满足有且仅有在 \(\text{bitcnt}(s)=i\) 的位置有值,值为 \(f_s\),则这个状态的总方案数等于 \(g_{a_1},g_{a_2},...,g_{a_l}\) 的子集卷积。于是可以直接使用子集卷积计算,可以做到 \(O(2^nP(n)n^2)\) 左右的复杂度。但是还是不行。
注意到 \(\sum^l_{i=1}a_i=n\),且 \(g_{a_i}\) 仅仅在 \(\text{bitcnt}(a_i)\) 处有值。也就是说我们其实根本不需要使用子集卷积——子集卷积的方法是给每个集合幂级数增加一维长度的限制,但是这里我们已经对长度进行了限制!假设有任何两个 \(s_i\) 有交,那么所有 \(s_i\) 的并的大小就不可能为 \(n\). 于是直接对 \(g_{a_i}\) 这些集合幂级数作 or 卷积即可。
枚举划分后,计算 or 卷积的时间复杂度为所有划分方案的总长度,足以通过。但是我们可以边 DFS 边维护 or 卷积,复杂度变成了搜索树的节点个数乘以 \(2^n\).
划分数搜索时,比较好的方法是从大到小搜索,每次放的数不超过上次放的。这时只要上次放的数不小于 \(2\),每个节点分叉数就一定大于 \(1\). 假设剩下一堆 \(1\) 是一起放的,那么节点数显然为 \(O(P(n))\);否则据 EI 爷说是 \(O(P(n)\sqrt n)\) 的。这里可以预处理 \(g_1\) 的幂来做到前者的复杂度。
总时间复杂度 \(O(2^n(n^2+T(n))\),其中 \(T(n)=O(P(n))\) 或 \(O(P(n)\sqrt n)\) 或 \(O(\text{sum of length of all partitions})\).
代码
#include<bits/stdc++.h>
#define llong long long
#define mkpr make_pair
#define x first
#define y second
#define iter iterator
#define riter reversed_iterator
#define y1 Lorem_ipsum_dolor
using namespace std;inline int read()
{int x = 0,f = 1; char ch = getchar();for(;!isdigit(ch);ch=getchar()) {if(ch=='-') f = -1;}for(; isdigit(ch);ch=getchar()) {x = x*10+ch-48;}return x*f;
}const int mxN = 18;
int bitcnt[(1<<mxN)+3];
llong f[mxN+3][(1<<mxN)+3];
llong dp[(1<<mxN)+3][mxN+3];
llong g[mxN+3][(1<<mxN)+3];
int part[mxN+3],aux[mxN+3];
llong h[(1<<mxN)+3];
char a[mxN+3][mxN+3];
int n,m;void dfs(int rst,int lst)
{if(rst==0){llong ret = 0ll;for(int i=0; i<(1<<n); i++){ret += ((n-bitcnt[i])&1)?-g[m][i]:g[m][i];}
// printf("("); for(int i=1; i<=m; i++) printf("%d ",part[i]); printf("): %I64d\n",ret);for(int i=1; i<=m; i++) {aux[i] = part[m-i+1];}do{int pos = 0,sta = 0;for(int i=1; i<=m; i++){for(int j=1; j<aux[i]; j++,pos++) {sta|=(1<<pos);}pos++;}
// printf("sta=%d\n",sta);h[sta] += ret;} while(next_permutation(aux+1,aux+m+1));return;}for(int i=1; i<=rst&&i<=lst; i++){part[++m] = i;for(int j=0; j<(1<<n); j++) {g[m][j] = g[m-1][j]*f[i][j];}dfs(rst-i,i);m--;}
}int main()
{for(int i=1; i<(1<<mxN); i++) bitcnt[i] = bitcnt[i>>1]+(i&1);n = read(); for(int i=0; i<n; i++) {scanf("%s",a[i]); for(int j=0; j<n; j++) a[i][j] -= 48;}for(int i=0; i<n; i++) dp[1<<i][i] = 1ll;for(int i=1; i<(1<<n); i++) for(int j=0; j<n; j++) if(i&(1<<j)){llong x = dp[i][j];for(int k=0; k<n; k++) if(a[j][k]&&!(i&(1<<k))){dp[i|(1<<k)][k] += x;}}for(int i=0; i<(1<<n); i++) for(int j=0; j<n; j++) if(i&(1<<j)){f[bitcnt[i]][i] += dp[i][j];}
// for(int i=0; i<(1<<n); i++) printf("%I64d ",f[bitcnt[i]][i]); puts("");for(int i=0; i<n; i++) for(int j=0; j<(1<<n); j++) if(j&(1<<i)){for(int k=0; k<n; k++) {f[k][j] += f[k][j^(1<<i)];}}for(int i=0; i<(1<<n); i++) g[0][i] = 1ll; dfs(n,n);for(int i=0; i<n-1; i++) for(int j=0; j<(1<<n-1); j++) if(j&(1<<i)){h[j^(1<<i)] -= h[j];}for(int i=0; i<(1<<n-1); i++) printf("%I64d ",h[i]); puts("");return 0;
}
Codeforces 1326F Wise Men (容斥原理、状压 DP、划分数)相关推荐
- Codeforces 1326F Wise Men (容斥原理、状压 DP、子集和变换、划分数)
题目链接 F1: https://codeforces.com/contest/1326/problem/F1 F2: https://codeforces.com/contest/1326/prob ...
- Codeforces Gym 100676G Training Camp 状压dp
http://codeforces.com/gym/100676 题目大意是告诉你要修n门课,每门课有一个权值w[i], 在第k天修该课程讲获得k*w[i]的学习点数,给出了课程与先修课程的关系,要修 ...
- codeforces 8C. Looking for Order 状压dp
题目链接 给n个物品的坐标, 和一个包裹的位置, 包裹不能移动. 每次最多可以拿两个物品, 然后将它们放到包里, 求将所有物品放到包里所需走的最小路程. 直接状压dp就好了. #include < ...
- CodeForces - 1102F Elongated Matrix(哈密顿路径+状压dp)
题目链接:点击查看 题目大意:给出一个 n∗mn * mn∗m 的数字矩阵,现在可以对 行 进行重新排列,现在对排列后的矩阵按列展开成线性:s1,s2,-,snm=maze1,1,maze2,1,.. ...
- Educational Codeforces Round 13 E. Another Sith Tournament 状压dp
E. Another Sith Tournament 题目连接: http://www.codeforces.com/contest/678/problem/E Description The rul ...
- CodeForces - 1550E Stringforces(二分+状压dp)
题目链接:点击查看 题目大意:给出一个长度为 nnn 的字符串,只包含前 kkk 个小写字母以及通配符 ???,现在可以将通配符替换成任意的前 kkk 个字母中的一个.设 f[i]f[i]f[i] 为 ...
- 【uoj#37/bzoj3812】[清华集训2014]主旋律 状压dp+容斥原理
题目描述 求一张有向图的强连通生成子图的数目对 $10^9+7$ 取模的结果. 题解 状压dp+容斥原理 设 $f[i]$ 表示点集 $i$ 强连通生成子图的数目,容易想到使用总方案数 $2^{sum ...
- Codeforces Beta Round #8 C. Looking for Order 状压dp
题目链接: http://codeforces.com/problemset/problem/8/C C. Looking for Order time limit per test:4 second ...
- Codeforces ----- Kefa and Dishes [状压dp]
题目传送门:580D 题目大意:给你n道菜以及每道菜一个权值,k个条件,即第y道菜在第x道后马上吃有z的附加值,求从中取m道菜的最大权值 看到这道题,我们会想到去枚举,但是很显然这是会超时的,再一看数 ...
最新文章
- OVS vswitchd启动(三十六)
- android 设置控件的透明度
- MySQL: ERROR 1040: Too many connections”的异常情况1
- 闪电网络介绍以及试用 (上)
- [转载]_tmain main wmain WinMain
- 7zip暗色系图标(windows下)
- np.random.seed(0)作用
- 嵌入式知识概要(1)
- 在Ubuntu上使用FreeFileSync同步文件
- “极度郁闷,要求慰安”
- 基于semisync实现MySQL的主从半同步复制
- java分页查询代码实现
- 中国国家统计局2021年版行政区划完整版
- android腾讯离线推送,腾讯云IM离线推送设置
- 最权威的成都Java培训机构排名榜单公布啦,学Java必看
- 斐讯n1 linux连接wifi,斐讯 N1 部署 Docker 和 OpenWRT,并利用 Hostapd 开启 Wi-Fi 热点
- html--样式的建立style,css样式
- matlab error 15,为什么我遇到了“License Manager Error -15”的错误?
- VBA批量OCR识别提取身份证照片信息_手机扫描仪:直装就是VIP,不限次数,一秒钟就能提取图片中的文字...
- 云服务器同账号不同地域数据迁移的方法