题面
题意
给出n,m,k,求出n到m间有几个数的数字和与整个数都是k的倍数
方法
虽然k<10000,然而因为n,m小于2^31,数字和最大也就八十几,故大于85的直接输出0.
用前缀和维护一下,要求n到m,只需要求0~m - 0~n-1 即可.
dp时只需记录当前长度,数字和对k取模的结果和数对k取模的结果.
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll T,TT,n,m,k,dp[20][100][100],num[20],ten[]={1,1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000,10000000000,100000000000,1000000000000,10000000000000};//³¤¶È,Êý×ÖºÍÈ¡Ä£Óë×ÜÊýÈ¡Ä£
ll dfs(ll len,bool lim,ll szh,ll mod)
{
if(!len)
{
if(!szh&&!mod) return 1;
return 0;
}
if(!lim&&dp[len][szh][mod]!=-1) return dp[len][szh][mod];
ll mx=9,i,j,res=0;
if(lim) mx=num[len];
for(i=0;i<=mx;i++)
{
res+=dfs(len-1,lim&&i==mx,(k+szh-i)%k,(k+mod-i*ten[len]%k)%k);
}
if(!lim) dp[len][szh][mod]=res;
return res;
}
ll ys(ll u)
{
ll i,j;
i=0;
while(u)
{
i++;
num[i]=u%10;
u/=10;
}
// for(j=1;j<=i;j++) cout<<num[j]<<" ";
// cout<<endl;
return dfs(i,1,0,0);
}
int main()
{
ll i,j;
cin>>T;
TT=T;
while(T--)
{
memset(dp,-1,sizeof(dp));
scanf("%lld%lld%lld",&n,&m,&k);
printf("Case %lld: ",TT-T);
if(k>=85)
{
printf("0\n");
continue;
}
printf("%lld\n",ys(m)-ys(n-1));
}
}