现在的位置: 首页 > 综合 > 正文

hdu 3555 数位dp

2013年12月07日 ⁄ 综合 ⁄ 共 1044字 ⁄ 字号 评论关闭

这是最简单的数位dp,也是我第一道数位dp....话说以前这样的题,根本不敢下手。只有下手了,挑战了,才能逐步战胜困难。畏惧是永远不行的

对于数位的问题,要逐位化简。之前看了看cxlove大湿的博客,看了几行,也就是dp的状态和阶段,当然转移方程完全没看。

dp[i][0]:从0~(10^i-1)有多少个数不含“49”

dp[i][2]:从0~(10^i-1)有多少个数含“49”

重点是dp[i][1]:从0~(10^i-1)有多少个是不含“49”的且以9为打头的,这是个衔接状态,很重要

状态转移就看程序吧,因为这个搞了不少WA。。。。最后搜索时注重细节,附代码:

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <vector>

#define N 20
#define ll __int64 
#define ss(a) scanf("%I64d",&a)
#define pb push_back

using namespace std;

ll dp[N][4],a[N],c[N];
vector<int>b;
int x;

ll deal(int k)
{
    if (k<0) return x+1;
    if (k<x) return a[k]+1;
    else 
    {
        if (b[k]<=4) return b[k]*dp[k][2]+deal(k-1);
        else return b[k]*dp[k][2]+dp[k][1]+deal(k-1);
    }
}

int main()
{
    int i,T;
    ll n;
    dp[0][0]=1;c[0]=1;
    for (i=1;i<N;i++)
    {
        dp[i][0]=dp[i-1][0]*10-dp[i-1][1];
        dp[i][1]=dp[i-1][0];
        dp[i][2]=dp[i-1][2]*10+dp[i-1][1];
        c[i]=c[i-1]*10;
    }
    cin>>T;
    while (T--)
    {
        ss(n);
        b.clear();
        while (n>0)
        {
            int k=b.size();
            if (k==0) a[0]=n%10;
            else a[k]=(n%10)*c[k]+a[k-1];
            b.pb(n%10);
            n/=10;
        }
        x=-1;
        for (i=b.size()-2;i>=0;i--) 
            if (b[i+1]*10+b[i]==49) 
            {
                x=i;break;
            }
        printf("%I64d\n",deal(b.size()-1));
    }
    return 0;
}

 

抱歉!评论已关闭.