恨7不成妻
描述
单身!
依然单身!
吉哥依然单身!
DS 级码农吉哥依然单身!
所以,他平生最恨情人节,不管是 214 还是 77 ,他都讨厌!
吉哥观察了 214 和 77 这两个数,发现:
2+1+4=7
7+7=7×2
77=7×11
最终,他发现原来这一切归根到底都是因为和 7 有关!所以,他现在甚至讨厌一切和 7 有关的数!
什么样的数和 7 有关呢?如果一个整数符合下面三个条件之一,那么我们就说这个整数和 7 有关:
整数中某一位是 7 ;
整数的每一位加起来的和是 7 的整数倍;
这个整数是 7 的整数倍。
现在问题来了:吉哥想知道在一定区间内和 7 无关的数字的平方和。
输入
输入数据的第一行是测试数据组数 T ,然后接下来的 T 行表示 T 组测试数据。
每组数据在一行内包含两个正整数 L,R
输出
对于每组数据,请计算 [L,R] 中和 7 无关的数字的平方和,并将结果对 109+7取模后输出。
样例输入
3
1 9
10 11
17 17
样例输出
236
221
0
提示
对于全部数据,1≤T≤50,1≤L≤R≤1018
Analysis
虽然我也不知道还有三天就考联赛我做数位dp的题干什么,但这道题确实很妙啊
在看到要求平方和之前,一切都是数位dp的常见套路
然而我们还需要求平方和,这就需要一点技巧了
首先考虑简单一点的,我们来求一次方和(也就是在L~R之间所有满足要求的数的和)
假设当前位为
p
o
s
pos
pos,我们填入了一个
i
i
i,然后递归下去处理,返回的时候得到了当前位为i,后面全部都满足条件的数的个数
c
n
t
cnt
cnt
那么加上当前位的贡献,我们的一次方和就变成了
n
o
w
.
s
u
m
1
=
c
n
t
∗
i
∗
1
0
p
o
s
−
1
+
t
m
p
.
s
u
m
1
now.sum1=cnt*i*10^{pos-1}+tmp.sum1
now.sum1=cnt∗i∗10pos−1+tmp.sum1
(now.sum1表示算上当前位的一次方和,tmp.sum1表示不算当前位的一次方和)
现在考虑二次方和(a表示不算当前位,后面的数组成的数)
Σ
(
a
+
i
∗
1
0
p
o
s
−
1
)
2
\Sigma{(a+i*10^{pos-1})}^2
Σ(a+i∗10pos−1)2
拆开化简,令
b
=
i
∗
1
0
p
o
s
−
1
b=i*10^{pos-1}
b=i∗10pos−1就可以得到:
Σ
a
2
+
2
∗
b
∗
Σ
a
+
Σ
b
2
\Sigma{a^2}+2*b*\Sigma{a}+\Sigma{b^2}
Σa2+2∗b∗Σa+Σb2
然后就解决啦~~
Code
#include<bits/stdc++.h>
#define ll long long
#define P 1000000007
using namespace std;
int T,a[20],num=0;
ll l,r,two[20];
struct node{
ll sum1,sum2,cnt;//sum1-->a^1 sum2-->a^2 cnt-->a^0
node():sum1(0),sum2(0),cnt(0){}
}f[20][10][10];
inline node dp(int pos,int sum,int num,int limit){
if(!pos){
node tmp;
tmp.cnt=(bool)(sum&&num);
return tmp;
}
if(!limit&&f[pos][sum][num].cnt!=-1) return f[pos][sum][num];
int top=limit?a[pos]:9;
node res;
for(int i=0;i<=top;++i){
if(i==7) continue;
node tmp=dp(pos-1,(sum+i)%7,(num*10+i)%7,limit&&i==a[pos]);
res.cnt=(tmp.cnt+res.cnt)%P;
res.sum1=(tmp.cnt*1ll*i%P*two[pos-1]%P+tmp.sum1+res.sum1)%P;
res.sum2=(((res.sum2+tmp.sum2)%P+(2*two[pos-1]%P*1ll*i%P*tmp.sum1)%P)%P+(tmp.cnt*i*i%P*two[pos-1]%P*two[pos-1])%P)%P;
}
if(!limit) f[pos][sum][num]=res;
return res;
}
inline ll solve(ll x){
num=0;
while(x){
a[++num]=x%10;
x/=10;
}
return dp(num,0,0,1).sum2;
}
int main(){
memset(f,-1,sizeof(f));
scanf("%d",&T);
two[0]=1;
for(int i=1;i<=20;++i) two[i]=two[i-1]*10%P;
while(T--){
scanf("%lld%lld",&l,&r);
cout<<(solve(r)-solve(l-1)+P)%P<<'\n';
}
return 0;
}