Lighting (上下界数位dfs)

原题: https://cn.vjudge.net/problem/Gym-101954F

题意:

给一个n位2进制数a,求有多少个n位2进制b使a+b的二进制表示有恰好k个1

解析:

因为不考虑前缀0,所以b的取值范围为0~11…11,我们就得出了a+b的范围,跑一个带上下界的dfs即可

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL mod = 1e9+7;
char up[1009],down[1009];

int len,maxpos;

LL C[1009][1009];
void init(int n,int k){
    //////////////C
    for(int i=0;i<=1005;i++)C[i][0]=1;
    for(int i=1;i<=1005;i++){
        for(int j=1;j<=i;j++){
            C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
        }
    }
    //////////////up
    len=strlen(down+1);
    reverse(down+1,down+1+len);
    strcpy(up+1,down+1);
    up[len+1]='1';up[len+2]='\0';
    //////////////maxpos
    for(int i=1;;i++){
        if(up[i]=='1'){
            for(int j=1;j<i;j++)up[j]='1';
            up[i]='0';
            break;
        }
    }
    //cout<<up+1<<endl;
    maxpos=len;
    if(up[len+1]=='1')maxpos++;
}

LL dfs(int pos,int res,bool fup,bool fdown){
//当前位,剩余1,上下界满足与否
    if(pos==0)return res==0;
    if(pos<res)return 0;
    if(fup&&fdown)return C[pos][res];

    //剪枝:接下来全填1 只需考量上界
    if(pos==res){
        if(fup)return 1;
        else{
            if(!(up[pos]=='1'))return 0;
            else return dfs(pos-1,res-1,fup,fdown);
        }
    }

    //剪枝:接下来全填0 只需考量下界
    if(res==0){
        if(fdown)return 1;
        else{
            if(down[pos]=='1')return 0;
            else return dfs(pos-1,res,fup,fdown);
        }
    }

    //分几种情况
    LL ans=0;


    if(fup&&!fdown){
        if(down[pos]=='1'){
            ans+=dfs(pos-1,res-1,fup,fdown);
        }
        else{
            ans+=dfs(pos-1,res-1,fup,1);
            ans+=dfs(pos-1,res,fup,fdown);
        }
    }
    else if(!fup&&fdown){
        if(!(up[pos]=='1')){
            ans+=dfs(pos-1,res,fup,fdown);
        }
        else{
            ans+=dfs(pos-1,res,1,fdown);
            ans+=dfs(pos-1,res-1,fup,fdown);
        }
    }
    else{
        if((up[pos]=='1')&&(down[pos]=='1'))ans+=dfs(pos-1,res-1,fup,fdown);//1 1
        else if((up[pos]=='1')&&!(down[pos]=='1'))//1 0
            ans+=dfs(pos-1,res-1,fup,1),
            ans+=dfs(pos-1,res,1,fdown);
        else if(!(up[pos]=='1')&&!(down[pos]=='1'))//0 0
            ans+=dfs(pos-1,res,fup,fdown);
    }
    return ans%mod;
}

int main(){
    int n,k;
    cin>>n>>k>>down+1;
    init(n,k);
    LL ans=0;
    ans=dfs(maxpos,k,0,0);
    printf("%lld\n",ans);
}

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/84191649