数位DP,4维分别表示数的长度,数的最高位数字,数的各位上的和对7的余数,整个数对7的余数。
分别记录对应状态的数量,和,还有平方和。用到了(a+b)^2=a*a+b*b+2*a*b的原理。
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const __int64 MOD=1e9+7;
__int64 dp[21][11][9][9], ldp[21][11][9][9], ct[21][11][9][9];
__int64 p7[23], p10[23];
void init()
{
int i, j, k1, k2, k3;
__int64 tp;
p7[1]=p10[1]=1;
for(i=2;i<=21;i++){
p7[i]=p7[i-1]*10%7;
p10[i]=p10[i-1]*10%MOD;
}
memset(dp,0,sizeof(dp));
memset(ldp,0,sizeof(ldp));
memset(ct,0,sizeof(ct));
for(i=0;i<=9;i++) if(i!=7) dp[1][i][i%7][i%7]=i, ldp[1][i][i%7][i%7]=i*i, ct[1][i][i%7][i%7]=1;
for(i=2;i<=20;i++){
for(j=0;j<=9;j++){
if(j==7) continue;
for(k1=0;k1<=9;k1++) for(k2=0;k2<7;k2++) for(k3=0;k3<7;k3++){
tp=(p7[i]*j+k3)%7;
ct[i][j][(j+k2)%7][tp]+=ct[i-1][k1][k2][k3];
ct[i][j][(j+k2)%7][tp]%=MOD;
dp[i][j][(j+k2)%7][tp]+=dp[i-1][k1][k2][k3]+p10[i]*j%MOD*ct[i-1][k1][k2][k3]%MOD;
dp[i][j][(j+k2)%7][tp]%=MOD;
ldp[i][j][(j+k2)%7][tp]+=ldp[i-1][k1][k2][k3]+2*dp[i-1][k1][k2][k3]%MOD*p10[i]%MOD*j%MOD+p10[i]*j%MOD*p10[i]%MOD*j%MOD*ct[i-1][k1][k2][k3]%MOD;
ldp[i][j][(j+k2)%7][tp]%=MOD;
}
}
}
}
__int64 a[23];
__int64 deal(__int64 x)
{
int i, j, k1, k2, k3, tl=1;
while(x){
a[tl++]=x%10;
x/=10;
}
__int64 ans=0, pre=0, rem=0, trem=0;
for(i=tl-1;i>=1;i--){
for(j=0;j<a[i];j++){
if(j==7) continue;
for(k2=0;k2<7;k2++) for(k3=0;k3<7;k3++){
if((k2+rem)%7==0||(trem+k3)%7==0) continue;
ans+=ldp[i][j][k2][k3]+pre*pre%MOD*ct[i][j][k2][k3]%MOD+2*pre%MOD*dp[i][j][k2][k3]%MOD;
ans%=MOD;
}
}
if(a[i]==7) break;
pre=(pre+a[i]*p10[i])%MOD;
rem=(a[i]+rem)%7;
trem=(a[i]*p7[i]+trem)%7;
}
return ans;
}
int main() {
int t;
init();
scanf("%d",&t);
__int64 l, r;
while(t--){
scanf("%I64d%I64d",&l,&r);
printf("%I64d\n",(deal(r+1)-deal(l)+MOD)%MOD);
}
return 0;
}