zoukankan      html  css  js  c++  java
  • HDU 3652 B-number

    数位DP

    dp[i][j][k][m]表示最高位为i,数字j在首位,之前是否出现过13,余数是m的情况下的个数

    代码有详细注释,做完这题,感觉逐渐了解了数位DP

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #include <vector>
    #include <cmath>
    #include <map>
    #include <string>
    using namespace std;
    
    int dp[15][15][5][15];
    int tot,n;
    int p[20];
    
    bool cheak(int a,int b,int c,int d)
    {
        int res=a;
        for(int i=1;i<=b-1;i++) res=((res*10)%13);
        if((res+c)%13==d) return 1;
        return 0;
    }
    
    bool check2(int a,int b)
    {
        int num=0;
        for(int i=tot;i>=1;i--)
        {
            if(i>=a+1) num=num*10+p[i];
            else num=num*10;
        }
        if((num%13+b)%13==0) return 1;
        return 0;
    }
    
    void init()
    {
        memset(dp,0,sizeof dp);
    
        for(int j=0;j<=9;j++) dp[1][j][0][j]=1;
    
        for(int i=2;i<=10;i++)
        {
            for(int j=0;j<=9;j++)
            {
                for(int k=0;k<=1;k++)
                {
                    for(int l=0;l<=12;l++)
                    {
                        int sum=0;
                        if(k==0)//推到第i位的时候都没有13
                        {
                            for(int s=0;s<=9;s++)//枚举i-1位是多少
                            {
                                if(j==1&&s==3) continue;
                                for(int m=0;m<=12;m++)//枚举余数
                                    if(cheak(j,i,m,l))
                                        sum=sum+dp[i-1][s][0][m];
                            }
                            dp[i][j][k][l]=sum;
                        }
                        else if(k==1)//推到第i位的时候有13,可能之前就有13,也可能i位和i-1位产生了13
                        {
                            //之前就有13
                            for(int s=0;s<=9;s++)
                                for(int m=0;m<=12;m++)//枚举余数
                                    if(cheak(j,i,m,l))
                                        sum=sum+dp[i-1][s][1][m];
    
                            //i位和i-1位产生了13
                            for(int s=0;s<=9;s++)
                                if(j==1&&s==3)//这一位是1,上一位是3
                                    for(int m=0;m<=12;m++)//枚举余数
                                        if(cheak(j,i,m,l))
                                            sum=sum+dp[i-1][s][0][m];//从之前没有13的情况推导过来
                            dp[i][j][k][l]=sum;
                        }
                    }
                }
            }
        }
    }
    
    int f(int x)
    {
        tot=1;
        while(x)
        {
            p[tot++]=(x%10);
            x=x/10;
        }
        tot--;
    
        int res=0;
    
        //计算位数比tot小的总和
        for(int i=1;i<tot;i++)
        {
            for(int j=1;j<=9;j++)
            {
                res=res+dp[i][j][1][0];
            }
        }
    
        //计算位数为tot,但首位比x首位小的数量总和
        for(int i=1;i<p[tot];i++) res=res+dp[tot][i][1][0];
    
        //计算剩余部分
        bool flag=0;
        for(int i=tot-1;i>=1;i--)
        {
            for(int j=0;j<p[i];j++)
            {
                if(flag==0)
                {
                    if(j==3&&p[i+1]==1)
                    {
                        for(int m=0;m<=12;m++)
                        {
                            if(check2(i,m))
                            {
                                res=res+dp[i][j][0][m];
                                res=res+dp[i][j][1][m];
                            }
                        }
                    }
                    else
                    {
                        for(int m=0;m<=12;m++)
                        {
                            if(check2(i,m))
                            {
                                res=res+dp[i][j][1][m];
                            }
                        }
                    }
                }
                else if(flag==1)
                {
                    for(int m=0;m<=12;m++)
                    {
                        if(check2(i,m))
                        {
                            res=res+dp[i][j][0][m];
                            res=res+dp[i][j][1][m];
                        }
                    }
                }
            }
            if(p[i]==3&&p[i+1]==1) flag=1;//表示之前已经出现过13了
        }
    
        return res;
    }
    
    int main()
    {
        init();
        while(~scanf("%d",&n))
            printf("%d
    ",f(n+1));
        return 0;
    }
  • 相关阅读:
    SCRUM项目 4.0
    【操作系统】实验三 进程调度模拟程序
    Spring 计划
    backlog
    0505-NABCD模型、视频
    0429团队准备
    1028 C语言文法
    编译原理第二次作业 编译器任务总结
    1014编译原理第二次作业(修改版)
    算法原理与分析第二次作业
  • 原文地址:https://www.cnblogs.com/zufezzt/p/5167207.html
Copyright © 2011-2022 走看看