2019牛客暑假多校训练赛第七场H Pair(数位dp)

题目链接:https://ac.nowcoder.com/acm/contest/887/H

 

题意:给定A,B,C问在[1,A]和[1,B]中有多少对x,y满足x&y>C或者x^y<C.

数据范围:1<=A,B,C<=1e9

 

思路:数位dp,定义一个dp[len][lim1][lim2][ok1][ok2][za][zb]。len代表当前枚举的二进制位,lim1,lim2分别代表x和y的上限,ok1代表对于x&y>C是否成立,成立是1,有可能成立是0,不可能成立是-1,ok2代表对于x^y<C是否成立,1代表不成立,0代表可能成立,-1代表成立,za和zb分别代表x和y的数中是否出现了1,因为x和y的二进制位不能是全零。转移的话代码中非常容易看懂。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int t;
ll A,B,C,f[50],g[50],h[50];
ll dp[66][2][2][3][3][2][2];
ll dfs(ll len,ll lim1,ll lim2,ll ok1,ll ok2,ll za,ll zb){
    ll &ret=dp[len][lim1][lim2][ok1+1][ok2+1][za][zb];
    if(ret!=-1)return ret;
    if(len==0){
        ret=za&&zb&&(ok1>0||ok2<0);
        return ret;
    }
    ret=0; --len;
    int up1=lim1?1:f[len];
    int up2=lim2?1:g[len];
    for(int x=0;x<=up1;x++)for(int y=0;y<=up2;y++)
    ret+=dfs(len,lim1|(x<f[len]),lim2|(y<g[len]),ok1==0?(x&y)-h[len]:ok1,ok2==0?(x^y)-h[len]:ok2,za|x,zb|y);
    return ret;
}
int main(){
    scanf("%d",&t);
    while(t--){
        memset(dp,-1,sizeof(dp));
        scanf("%lld%lld%lld",&A,&B,&C);
        for(int i=0;i<30;i++){
            f[i]=A%2,A/=2;
            g[i]=B%2,B/=2;
            h[i]=C%2,C/=2;
        }
        printf("%lld\n",dfs(31,0,0,0,0,0,0));
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值