You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

75 lines
2.4 KiB

2 years ago
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 20;
const LL mod = 1e9 + 7;
LL a[N]; // 用于拆分十进制每一位的数组
LL base[N]; // 预处理出的10的幂次方
struct Node {
LL s0; // 满足条件数的个数 Σ(k,1)
LL s1; // 满足条件的数的和 Σ(k,A)
LL s2; // 满足条件的数的平方的和Σ(k,A^2)
} f[N][7][7];
/*
1u:
2sum: mod 7
3pre: mod 7
*/
// 枚举位置,每一位加起来的和%7,这个数%7,是不是贴上界
Node dfs(int u, int sum, int pre, bool op) {
// 1、当u==0时,当sum不是7的倍数,并且,pre不是7的倍数时,这个数是合法的,个数记为1返回
// 2、为什么返回的sum==0,pre==0呢因为这是要返回上一层去算的,这句话还需要仔细体会含义
if (u == 0) return {(sum && pre), 0, 0};
// 记忆化
if (!op && ~f[u][sum][pre].s0) return f[u][sum][pre];
// 上界
int up = op ? a[u] : 9;
// 本状态下u+sum+pre 的统计信息
Node ans = {0, 0, 0};
for (int i = 0; i <= up; i++) {
if (i == 7) continue;
Node ret = dfs(u - 1, (sum + i) % 7, (pre * 10 + i) % 7, op && (i == up));
// 汇集个数
ans.s0 = (ans.s0 + ret.s0) % mod;
// 汇集数字和
ans.s1 = (ans.s1 + ret.s0 * i % mod * base[u - 1] % mod + ret.s1) % mod;
// 汇集数字平方和
ans.s2 = (ans.s2 + i * base[u - 1] % mod * i % mod * base[u - 1] % mod * ret.s0 % mod) % mod;
ans.s2 = (ans.s2 + 2 * i % mod * base[u - 1] % mod * ret.s1 % mod + ret.s2) % mod;
}
// 套路
if (!op) f[u][sum][pre] = ans;
return ans;
}
LL calc(LL x) {
int al = 0;
while (x) a[++al] = x % 10, x /= 10;
return dfs(al, 0, 0, true).s2;
}
int main() {
// 与7无关的数是数字本身的特性而且取模是一个固定值不会因为多输入几次就变化
memset(f, -1, sizeof(f));
// 预处理出10的幂次方【因为涉及到取模要不这玩意还用预处理
base[0] = 1;
for (int i = 1; i < N; i++) base[i] = base[i - 1] * 10 % mod;
int T;
cin >> T;
LL l, r;
while (T--) {
cin >> l >> r;
printf("%lld\n", (calc(r) - calc(l - 1) + mod) % mod); // 操作的每一步都需要注意取模
}
return 0;
}