题目链接

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、划分数)相关推荐

  1. Codeforces 1326F Wise Men (容斥原理、状压 DP、子集和变换、划分数)

    题目链接 F1: https://codeforces.com/contest/1326/problem/F1 F2: https://codeforces.com/contest/1326/prob ...

  2. Codeforces Gym 100676G Training Camp 状压dp

    http://codeforces.com/gym/100676 题目大意是告诉你要修n门课,每门课有一个权值w[i], 在第k天修该课程讲获得k*w[i]的学习点数,给出了课程与先修课程的关系,要修 ...

  3. codeforces 8C. Looking for Order 状压dp

    题目链接 给n个物品的坐标, 和一个包裹的位置, 包裹不能移动. 每次最多可以拿两个物品, 然后将它们放到包里, 求将所有物品放到包里所需走的最小路程. 直接状压dp就好了. #include < ...

  4. CodeForces - 1102F Elongated Matrix(哈密顿路径+状压dp)

    题目链接:点击查看 题目大意:给出一个 n∗mn * mn∗m 的数字矩阵,现在可以对 行 进行重新排列,现在对排列后的矩阵按列展开成线性:s1,s2,-,snm=maze1,1,maze2,1,.. ...

  5. Educational Codeforces Round 13 E. Another Sith Tournament 状压dp

    E. Another Sith Tournament 题目连接: http://www.codeforces.com/contest/678/problem/E Description The rul ...

  6. CodeForces - 1550E Stringforces(二分+状压dp)

    题目链接:点击查看 题目大意:给出一个长度为 nnn 的字符串,只包含前 kkk 个小写字母以及通配符 ???,现在可以将通配符替换成任意的前 kkk 个字母中的一个.设 f[i]f[i]f[i] 为 ...

  7. 【uoj#37/bzoj3812】[清华集训2014]主旋律 状压dp+容斥原理

    题目描述 求一张有向图的强连通生成子图的数目对 $10^9+7$ 取模的结果. 题解 状压dp+容斥原理 设 $f[i]$ 表示点集 $i$ 强连通生成子图的数目,容易想到使用总方案数 $2^{sum ...

  8. 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 ...

  9. Codeforces ----- Kefa and Dishes [状压dp]

    题目传送门:580D 题目大意:给你n道菜以及每道菜一个权值,k个条件,即第y道菜在第x道后马上吃有z的附加值,求从中取m道菜的最大权值 看到这道题,我们会想到去枚举,但是很显然这是会超时的,再一看数 ...

最新文章

  1. OVS vswitchd启动(三十六)
  2. android 设置控件的透明度
  3. MySQL: ERROR 1040: Too many connections”的异常情况1
  4. 闪电网络介绍以及试用 (上)
  5. [转载]_tmain main wmain WinMain
  6. 7zip暗色系图标(windows下)
  7. np.random.seed(0)作用
  8. 嵌入式知识概要(1)
  9. 在Ubuntu上使用FreeFileSync同步文件
  10. “极度郁闷,要求慰安”
  11. 基于semisync实现MySQL的主从半同步复制
  12. java分页查询代码实现
  13. 中国国家统计局2021年版行政区划完整版
  14. android腾讯离线推送,腾讯云IM离线推送设置
  15. 最权威的成都Java培训机构排名榜单公布啦,学Java必看
  16. 斐讯n1 linux连接wifi,斐讯 N1 部署 Docker 和 OpenWRT,并利用 Hostapd 开启 Wi-Fi 热点
  17. html--样式的建立style,css样式
  18. matlab error 15,为什么我遇到了“License Manager Error -15”的错误?
  19. VBA批量OCR识别提取身份证照片信息_手机扫描仪:直装就是VIP,不限次数,一秒钟就能提取图片中的文字...
  20. 云服务器同账号不同地域数据迁移的方法

热门文章

  1. 第12课:优化神经网络——网络初始化技巧与超参数调试
  2. python numpy 子数组_Python快速转换numpy数组中Nan和Inf的方法实例说明
  3. QString to const char*
  4. 不是内部或外部命令也不是可运行的程序?
  5. 如何动态改变框架的大小[转]
  6. HTML中a标签/超链接标签的下划线怎么去掉
  7. 《Head First Servlets JSP(中文版)》书摘
  8. linux 内存显示括号内字母的含义
  9. 备份 CSDN 博客(上)
  10. 80x86描述符总结及解析描述符的小程序