hdoj 3652 数位dp

这道题大牛们都说水题,可是我刚开始做数位dp,感觉好吃力啊!

网上大部分都是用dfs写的,可惜我一开始和大家的入门思路就不一样,我一直习惯用递推。哎,感觉姿势不对啊。

递推预处理的复杂度更高一点。不过我觉得符合我的思维方式。没办法,改不了。

我就不说什么了,不要受我的思维影响,还是要学会大部分的思维方式才是正确的选择。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,ans;
__int64 bit[13];
int digit[13];
int dp[15][11][3][15];
void init()
{
    memset(dp,0,sizeof(dp));
    int i,j,k,m,x;
    bit[0]=1;
    for(i=1;i<=12;i++) bit[i]=bit[i-1]*10;
    dp[0][0][0][0]=1;
    for(i=1;i<=10;i++)
    {
        for(j=0;j<=9;j++)
        {
            for(m=0;m<=12;m++)
            {
                for(x=0;x<=9;x++)
                    for(k=0;k<=1;k++)
                if(k==1)
                {
                    dp[i][j][k][m]+=dp[i-1][x][1][(m-(j*bit[i-1]%13)+13)%13];
                    if(j==1&&x==3)
                        dp[i][j][k][m]+=dp[i-1][x][0][(m-(j*bit[i-1]%13)+13)%13];
                    //cout<<dp[i][j][k][m]<<endl;
                }
                else
                {
                    if(!(j==1&&x==3))
                    {
                        dp[i][j][k][m]+=dp[i-1][x][0][(m-(j*bit[i-1]%13)+13)%13];
                    }
                }
            }
        }
    }
}
void work(int num)
{
    int i,j,k,m,x;
    int len=0;
    memset(digit,0,sizeof(digit));
    while(num)
    {
        digit[++len]=num%10;
        num/=10;
    }
    digit[len+1]=0;
    ans=0;
    int flag=0,mod=0;
    for(i=len;i;i--)
    {
        for(j=0;j<digit[i];j++)
        {
           ans+=dp[i][j][1][(13-(mod*bit[i]%13))%13];
           if(flag||j==3&&digit[i+1]==1)
            ans+=dp[i][j][0][(13-(mod*bit[i]%13))%13];
        }
        if(digit[i]==3&&digit[i+1]==1) flag=1;
        mod=(mod*10+digit[i])%13;
    }
    printf("%d\n",ans);
}
int main()
{
    int i,j;
    int k,m;
    init();
    while(scanf("%d",&n)!=EOF)
    {
        work(n+1);
    }
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值