[bzoj4762]最小集合
来源:互联网 发布:经济学教材 知乎 编辑:程序博客网 时间:2024/06/05 01:15
题目描述
定义一个非空集合是合法的,当且仅当它满足以下两个条件。
1、集合内所有元素and和为0
2、它的非空子集中仅有它本身满足1
给出一个集合S,求它的合法非空子集数。
DP
先把给定集合所有数取反。
比如有效位数是4位,1101就变成0010。
那么问题变成,所有元素or和为1023,而去掉任意一个元素后or和均不为1023。
那么接下来我们来设一个诡异的状态。
因为要知道去掉一个人元素会不会使or和为1023,因此我们前后都要知道。
可以设一个f[i,j,k]表示做完了i个数,前面选择的一些数or和为j,我们希望后面选出的数or和为k。
然而随便推一推都觉得不会转移啊。。
这时赶紧改一下状态,设f[i,j,k]表示做完了i个数,前面选择的一些数or和为j,我们希望后面选出的数or和包含k(什么叫包含?x包含k需满足x&k=k)
设第i+1个数为x。
不选?
选呢?
假设后面部分不包含x时是k’。
我们发现k’需要满足两个条件:
1、k’|x=k(根据状态定义)
2、k’|j|x!=k’|j(如果等了那么就能去掉x了)
满足条件的k’肯定存在一些包含关系,而我么的状态设的也是包含,所以转移会比较方便。
先只考虑满足第一个条件:
f[i+1][j|x][k^(k&x)]+=f[i][j][k]
这个很容易考虑,如果k的某一位有1,x该位也有1,那么k’的这一位可以是0也可以为1。
再去掉满足第一个条件而不满足第二个条件的:
f[i+1][j|x][(k^(k&x))|(x^(x&j))]-=f[i][j][k]
这是个什么意思?先看后面,显然只有x的某一位是1,而j的对应位是0时才有1的贡献,意思就是x会给j的哪些原本没有1的位变成1。
而如果k’的这些位也有1,那么j|k’后,再或x将不变,因此会不满足第二个条件。
然后这个dp就是正确的,初始f[0][0][0]=1,最后答案是f[n][1023][0]。
假设有m位,这样做是
考虑优化吧。我们来证明,如果f[i][j][k]不为0,一定有j包含k。
初始时显然满足。
看第一条转移,f[i+1][j|x][k^(k&x)]+=f[i][j][k]。
假如j包含k,k的某位为0时,k&x的对应位肯定也是0,所以k^(k&x)并不会多1,反而可能少1,但j|x不会少1,因此有j|x包含k^(k&x)。
看第二条转移,f[i+1][j|x][(k^(k&x))|(x^(x&j))]-=f[i][j][k]。
假如j包含k,记k’=k^(k&x)。假如k’某位为1,可以不管它,由上面的结论j|x的这位也会是1。假如k某位为0,k’这位也是0,而x^(x&j)是1,那么最终这位会是1,而因为x^(x&j)的这位是1,x这位必须是1,那么j|x这位也有1了。
这样枚举j后每次只需枚举一个j包含的k,有个快捷的枚举方法见代码。
那么可以证明复杂度降为
#include<cstdio>#include<algorithm>#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;const int maxn=1000+10,N=1023,mo=1000000007;int a[maxn],f[N+10][N+10],g[N+10][N+10];int i,j,k,l,t,n,m,ans,x;int main(){ scanf("%d",&n); fo(i,1,n) scanf("%d",&a[i]),a[i]^=N; f[0][0]=1; fo(i,1,n){ fo(j,0,N){ k=j; while (1){ g[j][k]=0; if (!k) break; k=(k-1)&j; } } x=a[i]; fo(j,0,N){ //if ((x&j)==x) continue; k=j; while (1){ (g[j|x][k^(k&x)]+=f[j][k])%=mo; (g[j|x][(k^(k&x))|(x^(x&j))]-=f[j][k])%=mo; if (!k) break; k=(k-1)&j; } } fo(j,0,N){ k=j; while (1){ (f[j][k]+=g[j][k])%=mo; if (!k) break; k=(k-1)&j; } } } ans=f[N][0]; (ans+=mo)%=mo; printf("%d\n",ans);}
- BZOJ4762: 最小集合
- BZOJ4762 最小集合
- [bzoj4762]最小集合
- 【bzoj4762】【JZOJ5151】最小集合 题解
- [BZOJ4762]最小集合/[JZOJ5151]幻梦终醒
- 最小集合
- 最小支配集合板子
- 51nod 最小集合
- BZOJ 4762: 最小集合
- 51nod 1616 最小集合
- 51nod 1616 最小集合
- 51nod-1616 最小集合
- 51Nod-1616-最小集合
- 51nod 1616 最小集合
- 51nod 1616 最小集合
- stuts2与spring3最小结合jar集合
- [容斥] BZOJ 4762 最小集合
- 51 Nod 1616——最小集合
- linux下mysql oom killer
- ArrayList自动扩容解析
- Redis系列(二)--缓存设计(整表缓存以及排行榜缓存方案实现)
- JSON简介以及用法汇总
- 1002. 写出这个数 (20)
- [bzoj4762]最小集合
- LinearLayOut layout_gravity 与gravity 区别
- CentOS 下解决ssh登录 locale 警告
- javaScript中的异步操作
- map/unordered_map原理和使用整理
- AngularJs1.x自定义指令独立作用域的函数传入参数
- 打字机游戏Ⅱ之手速pk
- CSS样式上下左右渐变出现
- android studio之Lint代码质量控制提升