HDU 4507 吉哥系列故事——恨7不成妻
题目大意:
题解:
想到用数位dp来做,用\(preSum\)记录前面位的数字和\(\%7\),\(preMod\)记录前面位的数字的值\(\%7\)
\(cnt\)表示当前状态下与\(7\)无关的数的个数;
\(sum\)表示当前状态下与\(7\)无关的数的和;
\(sqSum\)表示当前状态下与\(7\)无关的数的平方和。
已知上一位的\(sum\),可得到当前的和为:\(nextSum=i\times 10^{pos}\times cnt+sum\)(\(i\)是当前选取的数)。
设某个数到第\(i\)位之前的值\(num\),则到第\(i\)位之后值为\(i\times 10^{pos} + num\),则它此时的平方为:
\[(i\times 10^{pos}+num)^2 = (i\times 10^{pos})^2+2\times i\times 10^{pos}\times num+num^2
\]
所以\(cnt\)个数的平方和就是:
\[\begin{aligned}
&(i\times 10^{pos})^2\times cnt+2\times i\times 10^{pos}\times num\times cnt+num^2\times cnt \\
=&(i\times 10^{pos})^2\times cnt+2\times i\times 10^{pos}\times SUM(num)+SUM(num^2) \\
=&(i\times 10^{pos})^2\times cnt+2\times i\times 10^{pos}\times sum+sqSum
\end{aligned}
\]
注意在运算中加入取余,因为取余的原因,可能结果为负,所以要加上\(mod\)再取余。
#include <cstring>
#include <iostream>
using namespace std;
#define ll long long
const int mod = 1e9 + 7;
struct Node {
ll cnt, sum, sqSum;
} dp[20][10][10];
int digit[20];
ll Bit[20];
Node dfs(int pos, int preSum, int preMod, bool limit) {
if (pos <= 0) {
return Node{preSum && preMod, 0, false};
}
if (!limit && dp[pos][preSum][preMod].cnt != -1) { // 没限制则用记忆化搜索
return dp[pos][preSum][preMod];
}
int up = limit ? digit[pos] : 9;
Node ans = Node{0, 0, false};
for (int i = 0; i <= up; ++i) {
if (i != 7) { // 排除有7的情况
Node temp = dfs(pos - 1, (preSum + i) % 7, (preMod * 10 + i) % 7, limit && i == up);
ans.cnt = (ans.cnt + temp.cnt) % mod; // 当前状态下与7无关的数的个数
ans.sum = (ans.sum + (Bit[pos] * i % mod * temp.cnt % mod + temp.sum) % mod) % mod; // 当前状态下与7无关的数的和
ans.sqSum = ((ans.sqSum + (temp.sqSum + 2 * Bit[pos] * i % mod * temp.sum % mod) % mod) % mod + i * Bit[pos] * i % mod * Bit[pos] % mod * temp.cnt % mod) % mod; // 当前状态下与7无关的数的平方和
}
}
if (!limit) dp[pos][preSum][preMod] = ans;
return ans;
}
void init() { // 10^x
Bit[1] = 1;
for (int i = 2; i < 20; ++i) {
Bit[i] = Bit[i - 1] * 10 % mod;
}
}
int cal(ll n) {
int cnt = 0;
while (n) {
digit[++cnt] = n % 10;
n /= 10;
}
return cnt;
}
int main() {
int T;
cin >> T;
init();
memset(dp, -1, sizeof(dp));
while (T--) {
ll l, r;
cin >> l >> r;
cout << (dfs(cal(r), 0, 0, true).sqSum - dfs(cal(l - 1), 0, 0, true).sqSum + mod) % mod << endl;
}
return 0;
}