[数位dp] hdu 3967 Zero's Numberd
题意:对于两个数i和k,把它分为两个部分的数,n和m。假设(n+m)%k=0 那么这算一种分法
比方 333可分成。3、33或者33、3。对于 (333,3)就等于2.
如今给出 a、b、k,为 (a~b,k)有多少种分法
思路:对于一个数。注意前导零并枚举分点就好了。
dp[22][22][22][22][2], 代表 i位,分点为fd。余数mod。对于k取余。是否有前导零
代码:
#include"cstdlib" #include"cstdio" #include"cstring" #include"cmath" #include"stack" #include"algorithm" #include"iostream" using namespace std; __int64 dp[22][22][22][22][2],ten[22]; //i位,分点为fd。余数mod,对于k取余,是否有前导零 int num[22],cnt; __int64 dfs(int site,int fd,int mod,int k,int ff,int f) { if(site==0) return mod?0:1; if(!f&&dp[site][fd][mod][k][ff]!=-1) return dp[site][fd][mod][k][ff]; int len=f?num[site]:9; __int64 ans=0; for(int i=0; i<=len; i++) { if(site>fd) { if(ff==0&&site==fd+1&&i==0) continue; //前导0不能到分点前,也就是前半部分不能为0 ans+=dfs(site-1,fd,(i*ten[site-fd]+mod)%k,k,ff||i!=0,f&&i==len); } else ans+=dfs(site-1,fd,(i*ten[site]+mod)%k,k,ff||i!=0,f&&i==len); } if(!f) dp[site][fd][mod][k][ff]=ans; return ans; } __int64 solve(__int64 x,int k) { cnt=0; if(x<10) return 0; __int64 ans=0; while(x) { num[++cnt]=x%10; x/=10; } for(int i=1; i<cnt; i++) //枚举分点 分界为这位之后 ans+=dfs(cnt,i,0,k,0,1); return ans; } int main() { __int64 a,b; int k; memset(dp,-1,sizeof(dp)); ten[1]=1; for(int i=2; i<=18; i++) ten[i]=ten[i-1]*10; while(scanf("%I64d%I64d%d",&a,&b,&k)!=-1) { printf("%I64d\n",solve(b,k)-solve(a-1,k)); } return 0; }