题意:对于两个数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;
}