枚举子集

枚举子集

发现自己经常记不住这个怎么写,就来写篇题解吧。

首先对于一个 n 位二进制数 x,求二进制位上都是 x 的子集的数有哪些,

比如:101的子集有100、001、000。

然后这个东西如果直接 2n 次枚举的话,复杂度就爆炸了。

所以可以用一个很厉害的东西,

代码长这样:

for(int i=(x-1)&x;i;i=(i-1)&x)

这个 i 直接就是枚举出来的子集了。

这个为啥是对的呢?

我的理解是,你普通枚举 i-- 了之后,可能出现一个地方 i 有个 1 但是 x0

所以你把 ix 与一下,来把这个 1 消掉就好了。

如果只求一个 x 的所有子集,那复杂度就是 2n

但是如果求 12n1 中的数字的所有子集,那这个的复杂度就是 3n

(好像是用什么二项式定理求出来的,但是蒟蒻不会qwq)

例题

P3773 [CTSC2017] 吉夫特

发现组合数可以用 lucas 分解一下,相当于对于 2ikabi 都要是 abi1 二进制位上的子集。

直接 dp,设 f[i] 表示以 i 结尾的合法子序列个数。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=3e5+10,mod=1e9+7;
int n,ans,f[N];
int main()
{
    scanf("%d",&n);
    for(int i=1,x;i<=n;i++)
    {
        scanf("%d",&x);
        for(int j=(x-1)&x;j;j=(j-1)&x)f[j]=(f[j]+f[x]+1)%mod;
        ans=(ans+f[x])%mod;
    }
    printf("%d",ans);
    return 0;
}
posted @   DLYdly1105  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示