poj3252 Round Numbers

突然发现好多DP练习没写blog

终于凭借自己的力量AC数位DP了(感动)

考虑维护两个数组,f[i][j][k]表示枚举到第i位,一共有j个0,是否有前导0,d数组在此基础上添加一个性质就是是否到达上界。

那么按定义转移记录答案就行了(好像和记忆化搜索没什么区别?)

 

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;

int len,a[40];
void getnum(int k)
{
    if(k==0){len=1;return ;}
    len=0;
    while(k>0)
    {
        a[++len]=k%2;
        k/=2;
    }
}

LL f[40][40][2],d[40][40][2];//第几位,几个0,有没有前导零 d是顶上界的 
int main()
{
    f[1][0][0]=1;f[1][1][1]=1;
    for(int i=2;i<=31;i++)
        for(int j=i;j>=0;j--)
            f[i][j][0]=f[i-1][j][0]+f[i-1][j][1],//填1
            f[i][j][1]=f[i-1][j-1][0]+f[i-1][j-1][1];//填0
    int L,R;
    while(scanf("%d%d",&L,&R)!=EOF)
    {
        LL ans=0;L--;
        
        getnum(L);
        memset(d,0,sizeof(d));
        d[1][1][1]=1;
        if(a[1]==1)d[1][0][0]=1;
        for(int i=2;i<=len;i++)
            for(int j=0;j<=i;j++)
                if(a[i]==1)
                {
                    d[i][j][0]=d[i-1][j][0]+d[i-1][j][1];
                    if(j>=1)d[i][j][1]=f[i-1][j-1][0]+f[i-1][j-1][1];
                }
                else
                {
                    if(j>=1)d[i][j][1]=d[i-1][j-1][0]+d[i-1][j-1][1];
                }
        for(int i=1;i<len;i++)
            for(int j=i/2+i%2;j<=i;j++)
                ans-=f[i][j][0];
        for(int j=len/2+len%2;j<=len;j++)
            ans-=d[len][j][0];
            
        getnum(R);
        memset(d,0,sizeof(d));
        d[1][1][1]=1;
        if(a[1]==1)d[1][0][0]=1;
        for(int i=2;i<=len;i++)
            for(int j=0;j<=i;j++)
                if(a[i]==1)
                {
                    d[i][j][0]=d[i-1][j][0]+d[i-1][j][1];
                    if(j>=1)d[i][j][1]=f[i-1][j-1][0]+f[i-1][j-1][1];
                }
                else
                {
                    if(j>=1)d[i][j][1]=d[i-1][j-1][0]+d[i-1][j-1][1];
                }
        for(int i=1;i<len;i++)
            for(int j=i/2+i%2;j<=i;j++)
                ans+=f[i][j][0];
        for(int j=len/2+len%2;j<=len;j++)
            ans+=d[len][j][0];
            
        printf("%lld\n",ans);
    }
    return 0;
}

 

posted @ 2018-08-22 08:43  AKCqhzdy  阅读(122)  评论(0编辑  收藏  举报