总是有点似懂非懂的,本代码摘自http://www.tuicool.com/articles/mqUBFz
几个容易易卡住的点:
1.记忆化搜索写的时候要将相同交错和的个数,相同交错和的数字的和分别进行dp
2.对于一位数字和两位数字的计算方式并不相同,要分数字的位数进行讨论。
3.由于结果可能比较大,每一步都需要使用同余定理,以防运算过程中爆long long的情况。
记忆化搜索的思路,
当前的交错和相同的数字的和=sum(待搜索的状态的数字和+当前搜索的数字的大小*当前搜索到的符合条件的数字个数)。
#include <cstdio>
#include <cstring>
long long mod=1000000007;
long long base[20];
long long l,r,k,bit[20],bt,yy;
struct node {
long long s,n;//s代表数字和,n代表数字个数
};
node dp[20][400];//状态转移
node dfs(long long pos,long long target,long long limit)//数位dp,基本可以算是模板啦
{
node t;
t.s=t.n=0;
if (pos==0) { //处理到最后一位,直接判断返回
if (target==100)
t.n=1;
return t;
}
if ((limit==0)&&(dp[pos][target].n!=-1)) return dp[pos][target];
long long tail=limit?bit[pos]:9;
long long sgn=((yy-pos)%2)?(-1):(1);//确定符号
long long head;
if (pos==yy)head =1;
else head=0;//确定搜索的起点和终点
for (int i=head;i<=tail;i++)
{
node tmp=dfs(pos-1,target-i*sgn,(limit==1)&&(i==bit[pos]));
if ((tmp.n)>0){
t.n+=tmp.n;
long long q;
q=((((tmp.n%mod)*base[pos])%mod)*i)%mod;//结果的同余处理
t.s+=(tmp.s)%mod;
t.s%=mod;
t.s+=q;
t.s%=mod;//每一步都要同余
}
}
if (limit==0) dp[pos][target]=t;
return t;
}
long long cal(long long x,long long y)
{
long long ans=0;
if (x==-1) return 0;
if (x==0) return 0;
bt = 0;
while (x)
{
bt++;
bit[bt]=x%10;
x/=10;
}
for (yy=1;yy<=bt;yy++){
memset(dp,-1,sizeof dp);
ans+=dfs(yy,y+100,yy==bt).s;//对于每个长度为yy的数字进行处理
ans=(ans+mod)%mod;
}
return ans;
}
int main()
{
base[1]=1;
for (int i=2;i<=19;i++)
base[i]=(base[i-1]*10)%mod;
scanf("%lld%lld%lld",&l,&r,&k);
{
printf("%lld",(cal(r,k)-cal(l-1,k)+mod)%mod);
}
return 0;
}