挺有意思的一道数位DP题。(本来想用普通的数位DP方法水过,然后就被数据艹了)
这题的解题思路是数位DP,但是需要进行一些加工。
定义f[i][j][k]表示当前已经(从高到低)处理了i位,数位和%7为j,数字%7为k的状态。
状态中记三个值,一个是以当前的数为前缀的合法数字个数c,一个是所有合法数字的数位和sum,一个是所有合法数字的平方和sqr。
考虑状态转移,设答案为ans,之后搜索的状态为k
- ans.c+=k.c
- ans.sum+=k.sum+i*pow[x]*k.c,因为我们枚举当前的位置k上放了i,则i在原数中对应i*10^x
- ans.sqr+=k.sqr+2*k.sum*i*pow[x]+i*pow[x]*i*pow[x]*k.c,这个是根据平方和公式搞出来的,大家可以脑补一下。
附上AC代码:
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const int p=1e9+7;
struct note{
ll c,sum,sqr;
}f[20][10][10];
int t,len,a[20];
ll n,m,pow[20];
inline note so(int x,int sum,int num,bool b){
if (!x) return (note){sum&&num,0,0};
if (!b&&f[x][sum][num].c!=-1) return f[x][sum][num];
note k={0},ans={0};
int lim=b?a[x]:9;
for (int i=0; i<=lim; ++i)
if (i!=7){
k=so(x-1,(sum+i)%7,(num*10+i)%7,b&&i==lim);
ans.c=(ans.c+k.c)%p;
ans.sum=((ans.sum+k.sum)%p+i*pow[x]%p*k.c%p)%p;
ans.sqr=(ans.sqr+(k.sqr+2*pow[x]*i%p*k.sum%p+(i*pow[x])%p*(i*pow[x])%p*k.c%p)%p)%p;
}
if (!b) f[x][sum][num]=ans;
return ans;
}
inline ll work(ll x){
len=0;
while (x) a[++len]=x%10,x/=10;
note k=so(len,0,0,1);
return k.sqr;
}
int main(void){
memset(f,-1,sizeof f),pow[1]=1;
for (int i=2; i<20; ++i) pow[i]=pow[i-1]*10ll%p;
for (scanf("%d",&t); t; --t) scanf("%lld%lld",&n,&m),printf("%lld\n",(work(m)-work(n-1)+p)%p);
return 0;
}