POJ 3252Round Numbers(数位DP)

来源:互联网 发布:大淘客数据接口怎么用 编辑:程序博客网 时间:2024/06/05 11:58

POJ 3252Round Numbers

题目大意

如果一个数的二进制中0的数目大于等于1那么就称这个数为Round Number,问你区间[L,R]中有多少Round Number,(1LR2109)

分析

问题可以转化成问从1到n有多少个Round Number

用f[i]表示2i之前的Round Number数目

dp[i][j]表示长为i,0和1的数目差为j的情况数。

接下来就是状态的转移了,状态的转移稍微麻烦一点,

比如1010
然后1000~1001
最后1010~1010
大概就是这个思路,具体见代码。

一开始交了几发WA后手动测试几组小数据都对了,看代码后发现有些int应该改成long long int,改后又WA,查了一会差不出,到网上找了份AC代码对拍发现131072后的数据就不对了,这么小不会是int的问题,最后才发现是dp[i][j]数组中j开小了。

这道题折腾了我快一天了,心累。

我的方法不太优美,可以参考这篇POJ3252:Round Numbers(数位DP+记忆化DFS)

代码

#include<cstdio>#include<iostream>#include<cmath>#include<cstring>#include<cstdlib>#include<queue>using namespace std;#define  LL long long intLL Start,Finish;LL dp[35][70];//dp[i][j]表示长为i,0和1的数目差为j的情况数,j为31时表示01差的数目为0LL f[35];//f[i]表示2^i之前(不包含2^i)的Round Number数目void Dp(){      dp[1][32]=1;//边界      dp[1][30]=1;      for(int i=2;i<=31;i++)//总长为i的情况            for(int k=1;k<=i-1;k++)//长为k的情况                  for(int j=31-i;j<=31+i;j++)//0和1差的数目                        dp[i][i-k-1-1+j]+=dp[k][j];}void Get_f(){      f[0]=1;//边界      LL temp_ans=0;      for(int i=1;i<=31;i++)      {            for(int j=31;j<=31+i;j++)                  temp_ans+=dp[i][j];            f[i]=temp_ans;      } }void To2(LL n,int b[],int &lenth)//将n转换成二进制存到b数组中,下标从0开始,lenth是最终二进制长度{      lenth=0;      while(n)      {            b[lenth++]=n%2;            n=n/2;      }}LL Solve(LL n)//求从0到n有多少Round number{    if(n<=1)return 1;    LL ans=0;    int b[35];    int lenth;    To2(n,b,lenth);    int diff=-1;//到目前为止的01差    ans=f[lenth-1];    for(int loc=lenth-2;loc>=0;loc--)    {         if(loc==0)//边界         {              if(b[loc]==1 )              {                   if(diff-1>=0)ans++;                   if(diff+1>=0)ans++;              }              else if(b[loc]==0 && diff+1>=0)ans++;              return ans;         }         if(b[loc]==1)         {                for(int i=1;i<=loc;i++)                    for(int j=31-i;j<=31+i;j++)                        if(diff+j+loc+1-i>=31)                            ans+=dp[i][j];                 diff--;         }         else diff++;    }    return ans;}int main(){    //freopen("data.in","r",stdin);    //freopen("data1.out","w",stdout);    LL ans;    Dp();    Get_f();    while(scanf("%lld%lld",&Start,&Finish)!=EOF)    {         ans=Solve(Finish)-Solve(Start-1);         printf("%lld\n",ans);    }}
0 0