HDOJ3652解题报告【数位DP】

题目地址:

  http://acm.hdu.edu.cn/showproblem.php?pid=3652

题目概述:

  给出一个数n,求出1~n中所有包含“13”并且是13的倍数的数的个数。例如13满足条件,而143虽然是13的倍数,不过不包含“13”,所以不满足条件。

大致思路:

  这种类型的题应该很容易看出是数位DP,这里设f[i,j,k,l]表示i位数当前位是j,这个数mod13=k的情况,l=1表示包含“13”,l=0表示不包含。

  转移的话详见代码。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <ctime>
#include <map>
#include <stack>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;

#define sacnf scanf
#define scnaf scanf
#define scanfi(x) scanf("%d",&x)
#define scanfd(x) scanf("%lf",&x)
#define scanfl(x) scanf("%lld",&x)
#define scanfc(x) scanf("%c",&x)
#define scanfs(x) scanf("%s",&x)
#define maxn  110
#define maxm 10
#define inf 1061109567
#define Eps 0.00001
const double PI=acos(-1.0);
#define mod 1000000007
#define MAXNUM 10000
void Swap(int &a,int &b) {int t=a;a=b;b=t;}
int Abs(int x) {return (x<0)?-x:x;}
typedef long long ll;
typedef unsigned int uint;

int f[11][10][13][2];           //f[i,j,k,l]   i位数当前为是j,mod13=k的情况,l=1表示包含13
int num[11];

int power(int a,int b)
{
    int ans=1;
    while(b)
    {
        if(b&1) ans*=a;
        a*=a;b>>=1;
    }
    return ans;
}

int calc(int x)
{
    int cnt=0,ans=0,temp=0;
    while(x)
    {
        num[cnt++]=x%10;
        x/=10;
    }
    num[cnt]=0;bool flag=false;
    for(int i=cnt-1;i>=0;i--)
    {
        for(int j=0;j<num[i];j++)
        {
            ans+=f[i+1][j][(13-temp%13)%13][1];
            if(flag) ans+=f[i+1][j][(13-temp%13)%13][0];
            else if(j==3&&num[i+1]==1) ans+=f[i+1][j][(13-temp%13)%13][0];
        }
        if(num[i+1]==1&&num[i]==3) flag=true;
        temp+=num[i]*power(10,i);
    }
    return ans;
}

int main()
{
    //freopen("data.in","r",stdin);
    //freopen("data.out","w",stdout);
    //clock_t st=clock();
    int n;
    for(int i=0;i<10;i++) f[1][i][i][0]=1;
    for(int i=2;i<=10;i++)
    {
        for(int j=0;j<10;j++)
        {
            for(int k=0;k<10;k++)
            {
                for(int l=0;l<13;l++)
                {
                    f[i][j][(l+j*power(10,i-1))%13][1]+=f[i-1][k][l][1];
                    if(j==1&&k==3)
                    {
                        f[i][j][(l+j*power(10,i-1))%13][1]+=f[i-1][k][l][0];
                    }
                    else f[i][j][(l+j*power(10,i-1))%13][0]+=f[i-1][k][l][0];

                }
            }
        }
    }
    while(~scanf("%d",&n))
    {
        int ans=calc(n+1);
        printf("%d\n",ans);
    }
    //clock_t ed=clock();
    //printf("\n\nTime Used : %.5lf Ms.\n",(double)(ed-st)/CLOCKS_PER_SEC);
    return 0;
}

 

posted @ 2017-04-14 10:57  CtrlKismet  阅读(194)  评论(0编辑  收藏  举报