BZOJ2757 - Blinker的仰慕者(数位dp)
题目
Blinker 有非常多的仰慕者,他给每个仰慕者一个正整数编号。而且这些编号还隐藏着特殊的意义,即编号的各位数字之积表示这名仰慕者对Blinker的重要度。 现在Blinker想知道编号介于某两个值A,B之间,且重要度为某个定值K的仰慕者编号和。
题解
这题就像 淘金 和 方伯伯的商店之旅 各取一部分合成的。
预处理乘积的所有情况,然后离散化。求编号和的部分详见代码,要维护多一个信息。
注意K可能为0,我这里把0的情况单独提出来处理了。
#include <bits/stdc++.h>
#define endl '\n'
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define FILE freopen(".//data_generator//in.txt","r",stdin),freopen("res.txt","w",stdout)
#define FI freopen(".//data_generator//in.txt","r",stdin)
#define FO freopen("res.txt","w",stdout)
#define pb push_back
#define mp make_pair
#define seteps(N) fixed << setprecision(N)
typedef long long ll;
using namespace std;
/*-----------------------------------------------------------------*/
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
#define INF 0x3f3f3f3f
const int N = 1e5 + 10;
const int M = 20120427;
const double eps = 1e-5;
typedef pair<ll, ll> PII;
set<ll> num[2][10];
vector<ll> pd;
ll f[20][N];
ll f0[20][2];
ll cnt[20][N];
ll cnt0[20][2];
int di[20];
ll p10[50];
int get(ll v) {
int p = lower_bound(pd.begin(), pd.end(), v) - pd.begin() + 1;
if(p >= pd.size() || pd[p - 1] != v) return -1;
return p;
}
PII dfs(int p, ll st, int lmt, int lead) {
if(!p) {
return ((!lead) && (st == 1)) ? mp(1, 0) : mp(0, 0);
}
int tst = get(st);
if(!lead && !lmt && cnt[p][tst] >= 0) return mp(cnt[p][tst], f[p][tst]);
ll res = 0;
ll ct = 0;
int maxx = lmt ? di[p] : 9;
for(int i = 0; i <= maxx; i++) {
if(lead) {
if(!i) {
auto v = dfs(p - 1, st, lmt && i == maxx, i == 0 && lead);
ct += v.first;
res += v.second + v.first % M * i % M * p10[p - 1] % M;
}
else if(st % i == 0) {
auto v = dfs(p - 1, st / i, lmt && i == maxx, i == 0 && lead);
ct += v.first;
res += v.second + v.first % M * i % M * p10[p - 1] % M;
}
} else if(i && st % i == 0) {
auto v = dfs(p - 1, st / i, lmt && i == maxx, i == 0 && lead);
ct += v.first;
res += v.second + v.first % M * i % M * p10[p - 1] % M;
}
res %= M;
}
if(!lmt && !lead) {
f[p][tst] = res;
cnt[p][tst] = ct;
}
return mp(ct, res);
}
PII dfs0(int p, bool st, int lmt, int lead) {
if(!p) {
return ((!lead) && (st)) ? mp(1, 0) : mp(0, 0);
}
if(!lead && !lmt && cnt0[p][st] >= 0) return mp(cnt0[p][st], f0[p][st]);
ll res = 0;
ll ct = 0;
int maxx = lmt ? di[p] : 9;
for(int i = 0; i <= maxx; i++) {
if(lead) {
if(!i) {
auto v = dfs0(p - 1, st, lmt && i == maxx, 1);
ct += v.first;
res += v.second + v.first % M * i % M * p10[p - 1] % M;
}
else {
auto v = dfs0(p - 1, st, lmt && i == maxx, 0);
ct += v.first;
res += v.second + v.first % M * i % M * p10[p - 1] % M;
}
} else {
auto v = dfs0(p - 1, st || (i == 0), lmt && i == maxx, 0);
ct += v.first;
res += v.second + v.first % M * i % M * p10[p - 1] % M;
}
res %= M;
}
if(!lmt && !lead) {
f0[p][st] = res;
cnt0[p][st] = ct;
}
return mp(ct, res);
}
ll solve(ll x, ll k) {
int tot = 0;
while(x) {
di[++tot] = x % 10;
x /= 10;
}
if(k)
return dfs(tot, k, 1, 1).second;
else
return dfs0(tot, 0, 1, 1).second;
}
void init() {
p10[0] = 1;
for(int i = 1; i < 30; i++) {
p10[i] = p10[i - 1] * 10 % M;
}
for(int i = 1; i <= 9; i++) {
num[1][i].insert(i);
}
for(int i = 2; i <= 18; i++) {
for(int j = 1; j <= 9; j++) {
for(int k = 1; k <= j; k++) {
for(auto v : num[!(i % 2)][k]) {
num[i % 2][j].insert(v * j);
}
}
}
}
set<ll> tmp;
for(int i = 1; i <= 9; i++) {
for(auto v : num[0][i]) {
tmp.insert(v);
}
for(auto v : num[1][i]) {
tmp.insert(v);
}
}
pd.push_back(0);
for(auto v : tmp) pd.push_back(v);
}
int main() {
IOS;
memset(cnt, -1, sizeof cnt);
memset(cnt0, -1, sizeof cnt0);
init();
int t;
cin >> t;
while(t--) {
ll a, b, k;
cin >> a >> b >> k;
if(get(k) < 0) cout << 0 << endl;
else cout << ((solve(b, k) - solve(a - 1, k)) % M + M) % M << endl;
}
}