Poj-3255 Round Numbers

[题目链接]

一个数的二进制中0的数量要不能少于1的数量。

// 非常非常非常推荐我转载的一篇大佬写的数位DP总结,Orz、

思路1: // 自己想哒 16ms
dp[pos][k]记录的是枚举到pos位,最多还能用k个1的数量。可用1的数量是随着枚举数不同而变化的。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;

int n,m;
int a[50];
int dp[50][100];

int dfs(int pos,int len,int k,bool limit,bool lead){ //k记录的是已经用了1的个数
    if(len/2-k<0)return 0; //len/2-1记录的是还可用1的个数
    if(pos==-1)return 1;
    if(!limit&&!lead&&dp[pos][len/2-k]!=-1)return dp[pos][len/2-k];
    int ans=0;
    int up=limit?a[pos]:1;
    for(int i=0;i<=up;i++){//len记录的是第一个二进制数从1开始的长度(前导0,长度减1)
        if(lead&&i==0)ans+=dfs(pos-1,len-1,k+i,limit&&i==a[pos],1);
        else ans+=dfs(pos-1,len,k+i,limit&&i==a[pos],0);
    }
    if(!limit&&!lead)dp[pos][len/2-k]=ans;
    return ans;
}

int solve(int x){
    int pos=0;
    while(x){
        a[pos++]=x&1;
        x>>=1;
    }
    return dfs(pos-1,pos,0,1,1);
}

int main()
{
    scanf("%d%d",&n,&m);
    memset(dp,-1,sizeof(dp));
    printf("%d\n",solve(m)-solve(n-1));
    return 0;
}

思路2: // 大佬思路 0ms(Orz、)
这题的约束就是一个数的二进制中0的数量要不能少于1的数量,通过上一题,这题状态就很简单了,dp[pos][num],到当前数位pos,0的数量减去1的数量不少于num的方案数,一个简单的问题,中间某个pos位上num可能为负数(这不一定是非法的,因为我还没枚举完嘛,只要最终的num>=0才能判合法,中途某个pos就不一定了),这里比较好处理,Hash嘛,最小就-32吧(好像),直接加上32,把32当0用。这题主要是要想讲一下lead的用法,显然我要统计0的数量,前导零是有影响的。至于!lead&&!limit才能dp,都是类似的,自己慢慢体会吧。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;

int n,m;
int a[50];
int dp[50][100];

int dfs(int pos,int num,bool limit,bool lead){
    if(pos==-1)return num>=50;
    if(!limit&&!lead&&dp[pos][num]!=-1)return dp[pos][num];
    int ans=0;
    int up=limit?a[pos]:1;
    for(int i=0;i<=up;i++){
        if(lead&&i==0)ans+=dfs(pos-1,num,limit&&i==a[pos],1);
        else ans+=dfs(pos-1,num+(i==0?1:-1),limit&&i==a[pos],0);
    }
    if(!limit&&!lead)dp[pos][num]=ans;
    return ans;
}

int solve(int x){
    int pos=0;
    while(x){
        a[pos++]=x&1;
        x>>=1;
    }
    return dfs(pos-1,50,1,1);
}

int main()
{
    scanf("%d%d",&n,&m);
    memset(dp,-1,sizeof(dp));
    printf("%d\n",solve(m)-solve(n-1));
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zzti_xiaowei/article/details/80068536