文件详细信息
本文件的大小为 2378 字节。
/*
## 题目大意
如果一个整数符合下面三个条件之一,那么我们就说这个整数和 $7$ 有关:
1. 整数中某一位是 $7$;
2. 整数的每一位加起来的和是 $7$ 的整数倍;
3. 这个整数是 $7$ 的整数倍。
每次吉哥想知道在一定区间 $[l,r]$ 内和 7 无关的数字的平方和。答案对 $10^9+7$ 取模。
保证测试数据组数 $T \le 50$,$1 \le l,r \le 10^18$。
## 做法 1:数位 DP
数位和以及模 $7$ 的余数都很好解决,这道题唯一特别的一点就是要求平方和。我们发现,只要维护个数,就能维护一次方和(支持同时加上某一数这个操作),就能维护二次方和。
*/
#include<cstdio>
#include<cstring>
template<typename T>
void read(T&num){
int ch=getchar();
num=0;
while(ch<48||ch>57)ch=getchar();
while(ch>=48&&ch<=57)num=(num<<3)+(num<<1)+(ch^48),ch=getchar();
}
template<typename T>
void write(T a){
static int ch[20],cnt=0;
if(a<0)putchar('-'),a=-a;
if(a==0)putchar('0');
while(a)ch[cnt++]=a%10|48,a/=10;
while(cnt)putchar(ch[--cnt]);
}
typedef long long ll;
const int P=1000000007;
int T,pw10_7[20],pw10_P[20];
ll l,r;
int digit[20],cnt;
struct Data{
int cnt,sum,sum2;
}f[20][7][7];
Data operator+(const Data a,const Data b){
return Data{(a.cnt+b.cnt)%P,(a.sum+b.sum)%P,(a.sum2+b.sum2)%P};
}
Data operator+(const Data a,const int x){
return Data{a.cnt,int((a.sum+(ll)a.cnt*x)%P),int((a.sum2+2ll*a.sum*x+(ll)a.cnt*x%P*x)%P)};
}
bool operator!=(const Data a,const Data b){
return a.cnt!=b.cnt||a.sum!=b.sum||a.sum2!=b.sum2;
}
Data dfs(int cur,int lim,int sum,int remainder){
if(cur==-1)return remainder&&sum?Data{1,0,0}:Data{0,0,0};
if(!lim&&f[cur][sum][remainder]!=Data{-1,-1,-1})return f[cur][sum][remainder];
int d=lim?digit[cur]:9;
Data ans={0,0,0};
for(int i=0;i<=d;i++)
if(i!=7)
ans=ans+(dfs(cur-1,lim&&i==d,(sum+i)%7,(remainder+pw10_7[cur]*i)%7)+((ll)i*pw10_P[cur]%P));
if(!lim)f[cur][sum][remainder]=ans;
return ans;
}
int solve(ll x){
cnt=0;
while(x){
digit[cnt++]=x%10;
x/=10;
}
memset(f,-1,sizeof(f));
Data ans=dfs(cnt-1,1,0,0);
return ans.sum2;
}
int main(){
pw10_7[0]=1;
for(int i=1;i<20;i++)pw10_7[i]=pw10_7[i-1]*10%7;
pw10_P[0]=1;
for(int i=1;i<20;i++)pw10_P[i]=pw10_P[i-1]*10ll%P;
read(T);
while(T--){
read(l),read(r);
write((P+solve(r)-solve(l-1))%P),putchar('\n');
}
return 0;
}