• 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
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    Linux系统、版本、CPU、内存查看、硬盘空间
    Spring AOP 通过order来指定顺序
    关于 String.intern() 的思考
    java枚举类型构造方法为什么是private的
    Spring Cache 介绍
    Linux下redis的安装
    使用Spring实现读写分离( MySQL实现主从复制)
    Intellij Idea 13 快捷键(与Eclipse比对)以及基本的设置
    linux下tomcat的shutdown命令杀不死进程
    求N个元素的子集合个数
  • 原文地址:https://www.cnblogs.com/AKCqhzdy/p/9515624.html
Copyright © 2020-2023  润新知