有m种物品,n个箱子之中装着若干物品。问取出一些箱子后,所有m种物品都被选出的方案数。

m<=20,n<=106

这道题很妙啊 深刻地利用了容斥

看到n=20,我们就想到了状压和容斥。

怎么容斥呢?我们设A(s)表示状态为s的集合的数量,那么A(2^m-1)就是所求答案。但是这个不好做,那么我们用容斥放缩一下这个条件。我们设B(s)表示状态为s的子集的集合的数量,那么我们可以得到以111为例 B(111)=A(111)+B(110)+B(101)+B(011)-B(100)-B(010)-B(001)+B(000) 那么化简一下 A(111)=B(111)-B(110)-B(101)-B(011)+B(100)+B(010)+B(001)-B(000) 标准的容斥形式。那么剩下的问题就是求出B的值。

我们定义B(s)是s的子集的集合的数量,那么我们只要枚举s的子集就行了,统计数量只要在读入时统计一下就行了。但是枚举子集的复杂度是3^m,过不去,那么我们再优化。

这里我们用了一种分治的方法来优化复杂度,我们利用一种类似cdq分治的办法,把复杂度优化到m*2^m。具体见代码。

然后就是容斥了。

这里证明一下子集枚举的复杂度:我们不妨设二元对(s,t)。那么我们不妨用三进制来表达关系,0s是t的子集,1s和t没关系,2t是s的子集。那么这就是3^m了。

还有一种可以省去popcount的枚举子集的方法,就是用递归,但是程序中没有实现,想知道的可以留个言教导一下蒟蒻。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = , mod = ;
int n, all, m;
ll ans;
int c[N], d[N];
inline ll power(ll x, ll t)
{
ll ret = ;
for(; t; t >>= , x = x * x % mod) if(t & ) ret = ret * x % mod;
return ret;
}
void build(int l, int r)
{
if(l > r) return;
if(l == r) { c[l] = d[l]; return; }
int mid = (l + r) >> ;
build(l, mid); build(mid + , r);
for(int i = l; i <= mid; ++i) c[i + mid - l + ] = (c[i + mid - l + ] + c[i]) % mod;
}
int main()
{
scanf("%d%d", &n, &m); all = << m;
for(int i = ; i <= n; ++i)
{
int num, tot = ; scanf("%d", &num);
while(num--)
{
int x; scanf("%d", &x); --x;
tot |= ( << x);
}
++d[tot];
}
build(, all - );
for(int i = ; i < all; ++i)
{
int x = __builtin_popcount(i);
if((x % ) == (m % )) ans = (ans + power(, c[i])) % mod; else ans = ((ans - power(, c[i])) % mod + mod) % mod;
}
printf("%lld\n", ans);
return ;
}

最新文章

  1. OpenCASCADE PCurve of Topological Face
  2. CSS语法
  3. C#:注册机的实现【提供源代码下载】
  4. javaWEB中的ServletRequest,ServletResponse的使用,及简化Servlet方法
  5. ps前端切图常用快捷键
  6. 麒麟OS剽窃
  7. 批量修改文件后缀(Python)
  8. 转载:fstream和ifstream详细用法
  9. Javascript基础(2)
  10. Python新手学习基础之数据结构-列表2 添加
  11. Hello,world,l&#39;m coming!
  12. Android 开发笔记___SD卡基本操作__图片读取写入
  13. Linux 进程终止后自动重启
  14. ajaxFileUpload上传带参数,返回值改成json格式
  15. flutter stack
  16. Spring boot 多模块项目 + Swagger 让你的API可视化
  17. poj 2632 Crashing Robots(模拟)
  18. P3226 [HNOI2012]集合选数
  19. How to have matlab tic toc in C++?
  20. C# 使用KingAOP面向切面编程

热门文章

  1. SpringBoot第十六篇:自定义starter
  2. Vue如何引入icon图标
  3. 数据导出Excel,动态列
  4. 缩小Oracle目录下UNDOTBS01.DBF文件的大小
  5. java成员变量
  6. Android BGABadgeView:BGABadgeLinearLayout以整体线性布局作为BadgeView(3)
  7. hihoCoder#1109 最小生成树三&#183;堆优化的Prim算法
  8. HDU 5024
  9. Linux下汇编语言学习笔记50 ---
  10. 静态区间第k大(划分树)