hdu3652 B-number 数位dp

来源:互联网 发布:网络诈骗的常用方式 编辑:程序博客网 时间:2024/05/20 08:42

dfs版本

#include<bits/stdc++.h>using namespace std;typedef long long ll;int num[15];int dp[15][15][3];//dp[i][j][k]//i:数位//j:余数//k:3种状态,0-没有1,1-有1,2-有13//pos为当前处理的数位(权重表示法,也就是剩下pos+1位待填数)//mod-余数,have-状态;//lim-后面的数是否可以任意填,1-不可以,0-可以int dfs(int pos,int mod,int have,int lim){    int n,i,ans=0,mod_x,have_x;    //余数为0,有13,返回一种结果    if(pos<=0)        return mod==0&&have==2;    //已经搜索过了    if(!lim&&dp[pos][mod][have]!=-1)        return dp[pos][mod][have];    //判断本位枚举的范围    n=lim?num[pos]:9;    for(i=0;i<=n;i++)    {        mod_x=(mod*10+i)%13;//重新计算余数        have_x=have;        if(have==0&&i==1)            have_x=1;        if(have==1&&i!=1)            have_x=0;        if(have==1&&i==3)            have_x=2;        ans+=dfs(pos-1,mod_x,have_x,lim&&i==n);    }    //dp[pos][mod][have]要保存的是pos之后可以任意填的结果    //存在dfs(...,1)和dfs(...,0)的区别,如果lim=1时,记录dp可能会导致错误    //所以每一次dfs(...,1)都要重新计算    if(!lim)        dp[pos][mod][have]=ans;    return ans;}int main(){    int n,i;    while(~scanf("%d",&n))    {        memset(num,0,sizeof(num));        memset(dp,0xff,sizeof(dp));        i=0;        while(n)        {            num[++i]=n%10;            n/=10;        }        printf("%d\n",dfs(i,0,0,1));    }    return 0;}
0 0