牛客每日一题 和与或(数位DP)

和与或

https://ac.nowcoder.com/acm/problem/21336

传送门

也就是每一位二进制只能放在这个数中的某一个上面

每位数字不能超过,我们发现这非常像数位的过程

现在简化一下问题

的对数满足

很明显这就是一个数位,表示

枚举到二进制第位,卡不卡上界,卡不卡上界

然后只需要暴力考虑当前位二进制填还是填

填的话填在还是填在,然后更新上下界范围即可。

回到这个问题

发现完全就是一样的问题,只不过变成了个数

当然你也可以去转移

不过这里用二进制压缩一下状态会更好看

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 1e9+7;
int f[63][1<<12],r[13],n,bit[64];
int dfs(int x,int limit)
{
    if( x<0 )    return 1;
    if( f[x][limit]!=-1 )    return f[x][limit];
    int state = 0, ans = 0;
    for(int i=1;i<=n;i++)
        if( r[i]&bit[x] )    state |= bit[i];//枚举当前位置的枚举范围
    ans += dfs(x-1,limit|state );
    for(int i=1;i<=n;i++)//枚举这个1填在哪个数上面 
    {
        if( bit[i]&limit )//已经没有限制了,可以填 
            ans += dfs(x-1,limit|state );//取1,其他位有1的也变成无限制 
        else if( bit[i]&state )//当前位有限制,且可以放1
            ans += dfs(x-1,(limit|state)^bit[i] );//当前位置保持限制,其他位解除限制 
    }
    return f[x][limit] = ans%mod;
}
signed main()
{
    bit[0] = 1;
    for(int i=1;i<=62;i++)    bit[i] = bit[i-1]*2;
    memset( f,-1,sizeof f );
    cin >> n;
    for(int i=1;i<=n;i++)    scanf("%lld",&r[i] );
    cout << dfs(61,0);
}
全部评论
a卡不卡上界是什么意思
点赞 回复 分享
发布于 2021-01-29 10:47
聚聚您模数打错了 /可怜
点赞 回复 分享
发布于 2021-10-06 16:08
太妙了,本来都预感要打一大串的代码,结果就这么几行QwQ
点赞 回复 分享
发布于 2022-03-10 17:09

相关推荐

一个菜鸡罢了:哥们,感觉你的简历还是有点问题的,我提几点建议,看看能不能提供一点帮助 1. ”新余学院“别加粗,课程不清楚是否有必要写,感觉版面不如拿来写一下做过的事情,教育经历是你的弱势就尽量少写 2. “干部及社团经历”和“自我评价”删掉 3. 论文后面的“录用”和“小修”啥的都删掉,默认全录用,问了再说,反正小修毕业前肯定能发出来 4. 工作经验和研究成果没有体现你的个人贡献,着重包装一下个人贡献
点赞 评论 收藏
分享
评论
7
1
分享
牛客网
牛客企业服务