13 100 200 1000
1 1 2 2
#include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> #include<math.h> #include<stack> #include<queue> #include<set> #include<map> #include<vector> using namespace std; typedef long long LL; /* int dfs(int i, int s, bool e) { if (i==-1) return s==target_s; if (!e && ~f[i][s]) return f[i][s]; int res = 0; int u = e?num[i]:9; for (int d = first?1:0; d <= u; ++d) res += dfs(i-1, new_s(s, d), e&&d==u); return e?res:f[i][s]=res; } ~~f为记忆化数组; ~~i为当前处理串的第i位(权重表示法,也即后面剩下i+1位待填数); ~~s为之前数字的状态(如果要求后面的数满足什么状态,也可以再记一个目标状态t之类,for的时候枚举下t); ~~e表示之前的数是否是上界的前缀(即后面的数能否任意填)。 ~~for循环枚举数字时,要注意是否能枚举0,以及0对于状态的影响,有的题目前导0和中间的0是等价的, 但有的不是,对于后者可以在dfs时再加一个状态变量z,表示前面是否全部是前导0,也可以看是否是首位, 然后外面统计时候枚举一下位数。It depends. */ //dp[i][j][k],i表示位数,j表示余数,k=0表示“不含13”,k=1表示“不含13且末位为1”,k=2表示“含有13” LL n,dp[40][13][3]; int num[50]; //分别表示当前考虑的位置,前一个数字,当前余数,是否有限制,是否已经出现13 LL dfs(int pos,int pre,int mod,bool limit,bool flag) { if(pos==0) return flag&&(mod==0); if(!limit && flag && dp[pos][mod][0]!=-1) return dp[pos][mod][0]; if(!limit && !flag && pre!=1 && dp[pos][mod][2]!=-1) return dp[pos][mod][2]; if(!limit && !flag && pre==1 && dp[pos][mod][1]!=-1) return dp[pos][mod][1]; int end = limit?num[pos]:9; LL ans = 0; for(int i=0;i<=end;i++) { ans+=dfs(pos-1,i,(mod*10+i)%13,limit&&(i==end),flag||(pre==1&&i==3)); } if(!limit) { if(flag) dp[pos][mod][0] = ans; if(!flag && pre!=1) dp[pos][mod][2] = ans; if(!flag && pre==1) dp[pos][mod][1] = ans; } return ans; } LL work() { int len = 0; while(n) { num[++len] = n%10; n/=10; } return dfs(len,0,0,true,false); } int main() { memset(dp,-1,sizeof(dp)); while(scanf("%I64d",&n)!=EOF) { printf("%I64d\n",work()); } return 0; }
HDU 3652 B-number,布布扣,bubuko.com
原文地址:http://blog.csdn.net/demonstrate8/article/details/38659031