【题目】
Problem Description
单身!
依然单身!
吉哥依然单身!
DS 级码农吉哥依然单身!
所以,他生平最恨情人节,不管是
214
214
214 还是
77
77
77,他都讨厌!
吉哥观察了 214 214 214 和 77 77 77 这两个数,发现:
2
+
1
+
4
=
7
2+1+4=7
2+1+4=7
7
+
7
=
7
∗
2
7+7=7*2
7+7=7∗2
77
=
7
∗
11
77=7*11
77=7∗11
最终,他发现原来这一切归根到底都是因为和 7 7 7 有关!所以,他现在甚至讨厌一切和 7 7 7 有关的数!
什么样的数和 7 7 7 有关呢?
如果一个整数符合下面 3 3 3 个条件之一,那么我们就说这个整数和 7 7 7 有关——
- 整数中某一位是 7 7 7;
- 整数的每一位加起来的和是 7 7 7 的整数倍;
- 这个整数是 7 7 7 的整数倍;
现在问题来了:吉哥想知道在一定区间内和 7 7 7 无关的数字的平方和。
Input
输入数据的第一行是 c a s e case case 数 t t t( 1 ≤ t ≤ 50 1 \le t ≤ 50 1≤t≤50),然后接下来的 t t t 行表示 t t t 个 c a s e case case;每个 c a s e case case 在一行内包含两个正整数 l , r l, r l,r( 1 ≤ l ≤ r ≤ 1 0 18 1 \le l \le r \le 10^{18} 1≤l≤r≤1018)。
Output
请计算 [ l l l , r r r ] 中和 7 7 7 无关的数字的平方和,并将结果对 1 0 9 + 7 10^9 + 7 109+7 求模后输出。
Sample Input
3
1 9
10 11
17 17
Sample Output
236
221
0
【分析】
终于把这道题弄出来了。。。
看到数据范围,很显然是一道数位 d p dp dp 题
其实,如果只是统计与 7 7 7 无关的数的个数,就是常规操作,直接套板子就行了
但是现在是求平方和,该怎么办呢?
对每个节点都保存一个三元组, n u m num num 为合法的数的个数, s u m sum sum 为合法的数的和, s q u squ squ 为合法的数的平方和
首先,我们先思考简单一点的,怎么求与 7 7 7 无关的数的和
假设现在 d p dp dp 到了第 p o s pos pos 位,这一位填的数为 i i i,那么加上这一位 i i i 产生的贡献,和就是
n o w . s u m + = t e m p . s u m + t e m p . n u m ∗ i ∗ 1 0 p o s − 1 now.sum+=temp.sum+temp.num*i*10^{pos-1} now.sum+=temp.sum+temp.num∗i∗10pos−1
n o w . s u m now.sum now.sum 记录的就是当前位置的和, t e m p . s u m temp.sum temp.sum 是不算上当前位置(就是之前的数的和)的和
现在就考虑如何算平方和( a a a 表示不算上当前位,之前合法的数)
n o w . s q u = ∑ ( a + i ∗ 1 0 p o s − 1 ) 2 now.squ=\sum(a+i*10^{pos-1})^2 now.squ=∑(a+i∗10pos−1)2
令 b = i ∗ 1 0 p o s − 1 b=i*10^{pos-1} b=i∗10pos−1,并拆开来化简得到
n o w . s q u = ∑ ( a 2 + 2 a b + b 2 ) = ∑ a 2 + 2 b ∑ a + ∑ b 2 now.squ=\sum (a^2+2ab+b^2)=\sum a^2+2b\sum a+\sum b^2 now.squ=∑(a2+2ab+b2)=∑a2+2b∑a+∑b2
可以发现, ∑ a 2 \sum a^2 ∑a2 就是 t e m p . s q u temp.squ temp.squ, ∑ a \sum a ∑a 就是 t e m p . s u m temp.sum temp.sum,有关于 b b b 的暴力计算就行了
【代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
#define Mod 1000000007
using namespace std;
int a[20],Pow[20];
struct dp{long long num,sum,squ;}f[20][10][10][2];
dp search(int p,int v1,int v2,bool limit)
{
int i,up;
dp ans=(dp){0,0,0};
if(!p) return (dp){v1&&v2,0,0};
if(~f[p][v1][v2][limit].num) return f[p][v1][v2][limit];
up=limit?a[p]:9;
for(i=0;i<=up;++i)
{
if(i==7) continue;
dp temp=search(p-1,(v1+i)%7,(v2*10+i)%7,limit&&a[p]==i);
ans.num=(ans.num+temp.num)%Mod;
ans.sum=(ans.sum+temp.sum+1ll*i*Pow[p-1]%Mod*temp.num%Mod)%Mod;
ans.squ=(ans.squ+temp.squ+2ll*i*Pow[p-1]%Mod*temp.sum%Mod+temp.num*i*i%Mod*Pow[p-1]%Mod*Pow[p-1]%Mod)%Mod;
}
f[p][v1][v2][limit]=ans;
return ans;
}
long long solve(long long x)
{
int p=0;
while(x!=0)
{
a[++p]=x%10;
x/=10;
}
memset(f,-1,sizeof(f));
return search(p,0,0,true).squ;
}
int main()
{
int n,i;
long long l,r;
scanf("%d",&n);
Pow[0]=1;
for(i=1;i<20;++i)
Pow[i]=10ll*Pow[i-1]%Mod;
for(i=1;i<=n;++i)
{
scanf("%lld%lld",&l,&r);
printf("%lld\n",(solve(r)-solve(l-1)+Mod)%Mod);
}
return 0;
}