zoukankan      html  css  js  c++  java
  • 【学习笔记&训练记录】数位DP

    数位DP,即对数位进行拆分,利用数位来转移的一种DP,一般采用记忆化搜索,或者是先预处理再进行转移

    一个比较大略的思想就是可以对于给定的大数,进行按数位进行固定来转移记录答案

    区间类型的,可以考虑前缀和的思想,求[l,r]可以看做求[1,r]-[1,l)

    其实还有一种,是按照二进制建一颗0,1树来表示,来做,但是比并没有做过,以后再总结

    HDU-2089

    题目大意:对于区间[L,R]求有多少不包含'62'且不包含'4'的数,题目允许有前导零

    思路:

    数位DP,考虑F[i][j]表示位数为i,最高位为j的满足的个数

    预处理后,统计答案即可,统计答案大致就是固定每一位,进行统计

    CODE:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    int read()
    {
        int x=0,f=1; char ch=getchar();
        while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
        while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    int n,m;
    int F[10][10];
    void prework()
    {
        F[0][0]=1;
        for (int i=1; i<=7; i++)
            for (int j=0; j<=9; j++)
                for (int k=0; k<=9; k++)
                    if (j!=4 && !(j==6&&k==2))
                        F[i][j]+=F[i-1][k];
    }
    int Calc(int x)
    {
        int digit[10]={0},len=0,ans=0;
        while (x!=0) {digit[++len]=x%10; x/=10;}
        for (int i=len; i>=1; i--)
            {
                for (int j=0; j<=digit[i]-1; j++)
                    if (j!=4 && !(j==2&&digit[i+1]==6))
                        ans+=F[i][j];
                if (digit[i]==4 || (digit[i]==2&&digit[i+1]==6)) break;
            }
        return ans;
    }
    int main()
    {
        prework();
        n=read(),m=read(); if (n>m) swap(n,m);
        while (n!=0 && m!=0)
            {
                printf("%d
    ",Calc(m+1)-Calc(n));
                n=read(),m=read(); if (n>m) swap(n,m);
            }
        return 0;
    }

    HDU-3652

    题目大意:给定n,求到n中,包含'13'且被13整除的数的个数

    思路:

    设计状态F[i][j][k][0/1]表示位数为i,最高位为j的%13余k的数字包含和不包含13的个数

    那么同样预处理,这里不含前导零,需要额外做一个值去进行计算,计算到n以内的,计算n+1即可

    CODE:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    long long n;
    long long F[20][20][15][2];
    long long cf(int x,int y)
    {
        long long re=x;
        for (int i=0; i<y; i++) re*=10;
        return re;
    }
    void prework()
    {
        for (int i=0; i<=9; i++) F[1][i][i%13][1]=1;
        for (int i=2; i<=10; i++)
            for (int tmp,j=0; j<=9; j++)
                {
                    tmp=cf(j,i-1);
                    for (int k=0; k<=9; k++)
                        for (int l=0; l<13; l++)
                            {
                                F[i][j][(tmp+l)%13][0]+=F[i-1][k][l][0];
                                if (j==1 && k==3) 
                                    F[i][j][(tmp+l)%13][0]+=F[i-1][k][l][1];
                                else 
                                    F[i][j][(tmp+l)%13][1]+=F[i-1][k][l][1];
                            }
                }
    //    for (int i=1; i<=10; i++)
    //        for (int j=0; j<=9; j++)
    //            for (int k=0; k<13; k++)
    //                printf("%I64d %I64d
    ",F[i][j][k][1],F[i][j][k][0]);
    }
    long long Calc(long long x)
    {
        int digit[15]={0},len=0,f=0; long long ans=0;
        while (x) {digit[++len]=x%10; x/=10;}
        for (int i=0; i<=digit[len]-1; i++)
            ans+=F[len][i][0][0];
        long long tmp=cf(digit[len],len-1);
        for (int tt,i=len-1; i>=1; i--)
            {
                for (int j=0; j<=digit[i]-1; j++)
                    for (int k=0; k<13; k++)
                        {
                            if ((tmp+k)%13==0) ans+=F[i][j][k][0];
                            if ((tmp+k)%13==0 && (digit[i+1]==1 && j==3)) 
                                ans+=F[i][j][k][1];
                            else if ((tmp+k)%13==0 && f) ans+=F[i][j][k][1];
                        }
                if (digit[i]==3 && digit[i+1]==1) f=1;
                tmp+=cf(digit[i],i-1);
            }
        return ans;
    }
    int main()
    {
        prework();
        while (scanf("%lld",&n)!=EOF)
            printf("%lld
    ",Calc(n+1));
        return 0;
    }
  • 相关阅读:
    一个小判卷系统
    关于int main(int argc,char* argv[])详解
    2014微软编程之美复赛的解题报告
    解题报告CF266B 384A 339A
    由于第一天在博客园开博客,我随便写个解题报告吧,以前很少写
    阿里巴巴大数据竞赛
    新注册的博客,欢迎大家多多指教
    vue中forceupdate的使用
    钉钉小程序之参数有中文。encodeUri以及encodeURIComponent详解
    关于offsetX、offsetY、clientX、clientY、pageX、pageY、screenX、screenY的区别
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5446450.html
Copyright © 2011-2022 走看看