Problem Description
如果一个整数符合下面3个条件之一,那么我们就说这个整数和7有关——
1、整数中某一位是7;
2、整数的每一位加起来的和是7的整数倍;
3、这个整数是7的整数倍;
现在问题来了:吉哥想知道在一定区间内和7无关的数字的平方和。
思路:
参考博客:https://www.cnblogs.com/kuangbin/archive/2013/05/01/3053233.html
要求一个区间中和7无关的数的平方和。
需要用数位DP维护3个值:
1.与7无关的数的个数
2.与7无关的数的和
3、与7无关的数的平方和。
第一个 与7无关的数的个数,很好求。
第二个 1-25的和 = 20*6 +0+1+2+3+4+5 + 10*10 + (0+1+2+3+4+5+6+7+8+9)*2 用到这样的思想
第三个 23的平方 = (20 + 3)^2 = 20^2 + 2*20*3 + 3^2; 20-23的平方和 = (20 + 1)^2 + (20 + 2)^2 + (20 + 3)^2 = 3*20^2 + 2*20*(1+2+3) + 1^2 + 2^2 + 3^2; 用到这样的思想
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int MOD = 1e9+7;
struct node//核心点就是维护这三个变量
{
ll num, sum, sqsum;
};
node dp[25][10][10];
ll a[25], z[25];
node dfs(int pos, ll dsum, ll dnum, int limit)
{
if(pos == -1) {
node temp;
temp.num = dsum && dnum;
temp.sum = temp.sqsum = 0;
return temp;
}
if(!limit && dp[pos][dsum][dnum].num != -1) return dp[pos][dsum][dnum];
int up = limit ? a[pos] : 9;
node res;
res.num = res.sqsum = res.sum = 0;
for(int i = 0; i <= up; i++)
{
if(i == 7) continue;
node temp = dfs(pos-1, (dsum+i)%7, (dnum*10+i)%7, limit && i == a[pos]);
//核心点
res.num = (res.num + temp.num)%MOD;
res.sum += (((i*z[pos])%MOD*temp.num)%MOD + temp.sum)%MOD;
res.sum %= MOD;
res.sqsum += (((2*i*z[pos])%MOD)*temp.sum)%MOD;
res.sqsum %= MOD;
res.sqsum += (((((i*z[pos])%MOD * (i*z[pos])%MOD))%MOD * temp.num)%MOD + temp.sqsum)%MOD;
res.sqsum %= MOD;
//
}
if(!limit) return dp[pos][dsum][dnum] = res;
else return res;
}
ll solve(ll x)
{
int pos = 0;
while(x)
{
a[pos++] = x%10;
x /= 10;
}
return dfs(pos-1, 0, 0, 1).sqsum;
}
void init()
{
for(int i = 0; i <= 20; i++)
{
for(int j = 0; j <= 8; j++)
{
for(int k = 0; k <= 8; k++)
dp[i][j][k].num = -1;
}
}
z[0] = 1;
for(int i = 1; i <= 18; i++)
z[i] = (z[i-1]*10)%MOD;
}
int main()
{
int T;
scanf("%d", &T);
ll lt, rt;
init();
while(T--)
{
cin >> lt >> rt;
cout << (solve(rt) - solve(lt-1) + MOD)%MOD << endl;
}
return 0;
}