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;
    }
}
posted @ 2020-08-20 21:37  limil  阅读(124)  评论(0编辑  收藏  举报