题目链接
题意
求一定区间内和7无关的数字的平方和。
思路
数位DP求以下三种东西
设数位DP当前位为now,下次搜索为i,后缀位为nt
- cnt 与7无关数的个数,基础数位DP
- sum 与7无关数的和,now.sum = (i*10^pos)*nt.cnt+nt.sum
- q 与7无关数的平方和, n o w . q = ( i ∗ 1 0 p o s + n t . s u m ) 2 = i ∗ i ∗ 1 0 p o s ∗ 1 0 p o s + 2 ∗ i ∗ 1 0 p o s ∗ n t . s u m + n t . q now.q = (i*10^{pos}+nt.sum) ^2 = i*i*10 ^{pos}*10 ^{pos}+2*i*10 ^{pos}*nt.sum+nt.q now.q=(i∗10pos+nt.sum)2=i∗i∗10pos∗10pos+2∗i∗10pos∗nt.sum+nt.q
i
∗
i
∗
1
0
p
o
s
∗
1
0
p
o
s
i*i*10 ^{pos}*10 ^{pos}
i∗i∗10pos∗10pos出现nt.cnt次需要额外×nt.cnt
2
∗
i
∗
1
0
p
o
s
∗
n
t
.
s
u
m
2*i*10 ^{pos}*nt.sum
2∗i∗10pos∗nt.sum 无需×nt.cnt,因为nt.sum已经将当前搜索i的后缀的全部求和
n
t
.
q
=
n
t
.
s
u
m
∗
n
t
.
s
u
m
nt.q = nt.sum*nt.sum
nt.q=nt.sum∗nt.sum直接继承即可
代码
#include <stdio.h>
#include <string.h>
#define ll long long
struct Node
{
ll cnt, sum, q, f;
Node():cnt(0),sum(0),q(0),f(0){}
}dp[20][10][10];
ll num[20], mod = 1e9+7, de[20];
Node dfs(ll pos, ll limit, ll sum, ll now)
{
if(pos == -1)
{
Node nt;
if(sum && now) nt.cnt = 1;
return nt;
}
if(!limit && dp[pos][sum][now].f) return dp[pos][sum][now];
ll up = limit ? num[pos] : 9;
Node nt, tmp;
for(ll i = 0; i <= up; ++i)
{
if(i == 7) continue;
nt = dfs(pos-1, limit&&i==up, (sum*10+i)%7, (now+i)%7);
tmp.cnt += nt.cnt;
tmp.cnt %= mod;
tmp.sum += (nt.cnt*i%mod*de[pos]%mod+nt.sum)%mod;
tmp.sum %= mod;
tmp.q += (nt.q+2*nt.sum*(i*de[pos]%mod)%mod+(i*de[pos]%mod)*(i*de[pos]%mod)%mod*nt.cnt%mod)%mod;
tmp.q %= mod;
}
tmp.f = 1;
return limit ? tmp : dp[pos][sum][now] = tmp;
}
ll solve(ll n)
{
ll pos = 0;
while(n)
{
num[pos++] = n%10;
n /= 10;
}
return dfs(pos-1, 1, 0, 0).q;
}
int main()
{
ll t, l, r;
memset(dp,0,sizeof(dp));
de[0] = 1;
for(ll i = 1; i <= 20; ++i) de[i] = 10*de[i-1]%mod;
for(scanf("%lld",&t); t; --t)
{
scanf("%lld%lld",&l,&r);
printf("%lld\n",(solve(r)-solve(l-1)+mod)%mod);
}
return 0;
}