推荐博客:
https://www.cnblogs.com/bxd123/p/10974247.html
关键点:( i + j )2=i2 + 2 * i * j + j2, 123=1 * 102 + 2 * 101 + 3.
根据上面两个式子,我们可以推出,我们需要维护两个值,一个是已经枚举出来的所有数的总和,另一个是已经枚举出来的所有数的平方的总和。
代码如下:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
struct node
{
ll cnt,sum,sqrt_sum; //cnt表示与7无关的数,sum表示这些数的和,sqrt_sum表示这些数的平方和
node(){
cnt=sum=sqrt_sum=0;
};
}dp[20][7][7];
int digit[20];
ll p[20]={1}; //p[i]表示10^i
node dfs(int pos,int st1,int st2,bool limit) //st1表示数字和mod7,st2表示数mod7
{
if(pos==-1)
{
node temp;
if(st1&&st2) temp.cnt=1; //两者皆不为0时,才符合要求,个数返回1
return temp;
}
if(!limit&&dp[pos][st1][st2].cnt!=-1) return dp[pos][st1][st2];
node ans;
int up= limit? digit[pos]:9;
for(int i=0;i<=up;++i)
{
if(i==7) continue; //剪掉包含7的数
node temp=dfs(pos-1,(st1+i)%7,(st2*10+i)%7,limit&&i==digit[pos]); //dfs找出pos位后面符合要求的数
ans.cnt+=temp.cnt;
ans.cnt%=mod;
ans.sum+=(temp.sum+(p[pos]*i)%mod*temp.cnt%mod)%mod; //算出中间2*i*j的值,记得要乘temp.cnt
ans.sum%=mod;
ans.sqrt_sum+=(temp.sqrt_sum+(2*temp.sum)%mod*(p[pos]*i)%mod)%mod; //这个不用乘temp.cnt,理解好
ans.sqrt_sum%=mod;
ans.sqrt_sum+=(temp.cnt*(p[pos]*i)%mod*(p[pos]*i)%mod)%mod; //这个就要,也要理解好
ans.sqrt_sum%=mod;
}
if(!limit) dp[pos][st1][st2]=ans;
return ans;
}
node solve(ll n)
{
int pos=0;
while(n) digit[pos++]=n%10, n/=10;
for(int i=0;i<20;i++)
for(int j=0;j<7;j++)
for(int k=0;k<7;k++)
dp[i][j][k].cnt=-1;
return dfs(--pos,0,0,1);
}
int main()
{
for(int i=1;i<20;i++)
p[i]=(p[i-1]*10)%mod;
int T;
cin>>T;
while(T--)
{
ll l,r;
cin>>l>>r;
node t1=solve(l-1), t2=solve(r);
cout<<(t2.sqrt_sum+mod-t1.sqrt_sum)%mod<<endl;
}
return 0;
}