http://acm.hdu.edu.cn/showproblem.php?pid=4722
题目求A到B之间有多少个lucky number,它的定义是各位数加起来 能被10整除
我的做法是直接 for i,j,k 求出 dp[i][j]表示 前i位数中,各位和模10为j的方案数
也就是当i=5,dp[i][j]表示 1到 99999 的所有数 中 各位和模10为j的个数
那么实际我们要求的是【1,A】的个数,例如A=76543,这时我们拿1到99999的方案数dp[i][0] ,减去 dp[4][2] (因为所有第i位数以8开头的数中,只要后面四位的和取模为2,则加起来就可以整除10,所以去掉这部分),然后再减去dp[4][1](这部分是去掉9开头的部分),以此类推,得到了79999的方案,再得到76999的方案,再得到76599最后得到 【1,76543】的方案
【当然你可以直接从低位往高位推比较简单】
最后答案是 【1,B】-【1,A】,特判A是否为答案即可
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
using namespace std;
#define INF 0x3f3f3f3f3f3f3f
#define MAX 100005
__int64 dp[20][15];
int judge(__int64 x)
{
__int64 sum=0;
while(x)
{
sum+=x%10;
x/=10;
}
if (sum%10==0)return 1;
return 0;
}
int aa[20];
int sum[20];
int main()
{
//freopen("xl_in.txt","r",stdin);
int i,j,k;
dp[0][0]=1;
for (i=0;i<=18;i++)
{
for (j=0;j<=9;j++)
{
for (k=0;k<=9;k++)
{
dp[i+1][(k+j)%10]+=dp[i][j];
}
}
}
/*for (i=0;i<=1000;i++)
{
printf("%d ",);
}*/
int t,cas=0;
cin>>t;
while(t--)
{
__int64 a,b;
cin>>a>>b;
__int64 tmp=a;
int ok=0;
while(tmp)
{
aa[++ok]=tmp%10;
tmp/=10;
}
sum[ok+1]=0;
for (i=ok;i>=1;i--)
sum[i]=sum[i+1]+aa[i];
__int64 sum1=dp[ok][0];
for (i=ok;i>=1;i--)
{
for (j=9;j>aa[i];j--)
{
sum1-=dp[i-1][(10-((j+sum[i+1])%10))%10];
}
}
// printf("%d\n",sum1);
tmp=b;
ok=0;
while(tmp)
{
aa[++ok]=tmp%10;
tmp/=10;
}
sum[ok+1]=0;
for (i=ok;i>=1;i--)
sum[i]=sum[i+1]+aa[i];
__int64 sum2=dp[ok][0];
for (i=ok;i>=1;i--)
{
for (j=9;j>aa[i];j--)
{
sum2-=dp[i-1][(10-((j+sum[i+1])%10))%10];
}
}
//printf("%I64d\n",sum2);
__int64 ans=sum2-sum1;
if (judge(a)) ans++;
cas++;
printf("Case #%d: %I64d\n",cas,ans);
}
return 0;
}