码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj3679 数字之积

时间:2017-07-12 00:54:57      阅读:247      评论:0      收藏:0      [点我收藏+]

标签:stream   display   close   amp   lin   bool   check   include   状态   

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3679

【题解】

fateice怎么挑了这种题讲了一下午啊……日好难写啊

这题一眼看过去就是数位dp……

然后我们发现,积的质因子只有4种,每个也不会有很多,就有状态$f(i, j, n_2, n_3, n_5, n_7)$表示到第$i$位,最高位为$j$,当前数字之积$p = 2^{n_2}3^{n_3}5^{n_5}7^{n_7}$的方案数。

转移随便做,然后就是普通的数位dp统计答案的方法啊(我傻逼写错了一个地方调了好久)

当然不存$j$也能统计方案,麻烦点。

然后我们发现,就算不存$j$开不下$19 * 64 * 38 * 26 * 22$的数组啊。观察到当$n = 10^9$,最多只有不超过5200合法的$(n_2, n_3, n_5, n_7)$,开个map存下下标和值的对应关系,然后直接dp就行了。

还有这题是统计$(L,R]$的答案,不要看错了。。

复杂度$O(log(R) * 5200 * 10)$。

技术分享
# include <map>
# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm>
// # include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int M = 5e5 + 10, N = 6000 + 5;
const int mod = 1e9+7;
const int N2 = 64, N3 = 38, N5 = 26, N7 = 22, LG = 19;

int n; ll L, R;

struct pa {
    int n2, n3, n5, n7;
    pa() {}
    pa(int n2, int n3, int n5, int n7) : n2(n2), n3(n3), n5(n5), n7(n7) {}
    friend pa operator + (pa x, int p) {
        switch(p) {
            case 2: ++x.n2; break;
            case 3: ++x.n3; break;
            case 5: ++x.n5; break;
            case 7: ++x.n7; break;
            case 4: x.n2 += 2; break;
            case 9: x.n3 += 2; break;
            case 8: x.n2 += 3; break;
            case 6: ++x.n2, ++x.n3; break;
        }
        return x;
    } 
    friend pa operator + (pa x, pa y) {
        return pa(x.n2 + y.n2, x.n3 + y.n3, x.n5 + y.n5, x.n7 + y.n7);
    }
    friend bool operator == (pa x, pa y) { return x.n2 == y.n2 && x.n3 == y.n3 && x.n5 == y.n5 && x.n7 == y.n7; } 
    friend bool operator <(pa x, pa y) { return x.n2 < y.n2 || (x.n2 == y.n2 && x.n3 < y.n3) || (x.n2 == y.n2 && x.n3 == y.n3 && x.n5 < y.n5) || (x.n2 == y.n2 && x.n3 == y.n3 && x.n5 == y.n5 && x.n7 < y.n7); }
    friend bool operator >(pa x, pa y) { return x.n2 > y.n2 || (x.n2 == y.n2 && x.n3 > y.n3) || (x.n2 == y.n2 && x.n3 == y.n3 && x.n5 > y.n5) || (x.n2 == y.n2 && x.n3 == y.n3 && x.n5 == y.n5 && x.n7 > y.n7); }
}p[N]; int pn = 0;

inline bool cmp(pa x, pa y) {
    return x.n2 >= y.n2 && x.n3 >= y.n3 && x.n5 >= y.n5 && x.n7 >= y.n7;
}

map<pa, int> mp;

inline bool check(int n2, int n3, int n5, int n7) {
    ll ret = 1; if(ret > n) return false;
    for (int i=1; i<=n2; ++i) {
        ret = ret * 2;
        if(ret > n) return false;
    }
    for (int i=1; i<=n3; ++i) {
        ret = ret * 3;
        if(ret > n) return false;
    }
    for (int i=1; i<=n5; ++i) {
        ret = ret * 5;
        if(ret > n) return false;
    }
    for (int i=1; i<=n7; ++i) {
        ret = ret * 7;
        if(ret > n) return false;
    }
    return true;
}

ll f[LG + 2][10][N], sum[LG + 2]; 
inline void pre() {
    for (int a=0; a<=N2; ++a)
        for (int b=0; b<=N3; ++b)
            for (int c=0; c<=N5; ++c)
                for (int d=0; d<=N7; ++d) 
                    if(check(a, b, c, d)) {
                        p[++pn] = pa(a, b, c, d);
                        mp[p[pn]] = pn;
                    }
    pa t;
    for (int j=1; j<=9; ++j) {
        t = pa(0, 0, 0, 0) + j;
        if(mp.find(t) != mp.end()) f[1][j][mp[t]] = 1;
    }
    for (int i=1; i<=18; ++i) {
        for (int j=1; j<=9; ++j) { 
            for (int k=1; k<=pn; ++k) {
                if(!f[i][j][k]) continue; 
                for (int l=1; l<=9; ++l) {
                    t = p[k] + l;
                    if(mp.find(t) != mp.end()) f[i+1][l][mp[t]] += f[i][j][k];
                }
                sum[i] += f[i][j][k]; 
            }
        }
    }
}

int w[LG + 3], wn;
inline ll solve(ll x) {
    if(x == 0) return 0;
    wn = 0; ll tx = x, ret = 0;
    while(tx) {
        w[++wn] = tx % 10;
        tx /= 10;
    }
    for (int i=wn-1; i; --i) ret += sum[i];
//    cerr << ret << endl;
    pa cur = pa(0, 0, 0, 0); 
    for (int i=wn; i; --i) {
        for (int j=1; j<w[i]; ++j) {
            for (int k=1; k<=pn; ++k) 
                if(mp.find(p[k] + cur) != mp.end()) ret += f[i][j][k]; 
        }
        if(w[i] == 0) break;
        cur = cur + w[i];
        if(mp.find(cur) == mp.end()) break;
//        cout << i << ‘ ‘ << ret << endl;
    } 
    return ret;
}
            
int main() {
    cin >> n >> L >> R;
    pre();
    cout << solve(R) - solve(L);
    return 0;
}
/*
233
1234 123423
ans = 14466
*/
View Code

 

bzoj3679 数字之积

标签:stream   display   close   amp   lin   bool   check   include   状态   

原文地址:http://www.cnblogs.com/galaxies/p/bzoj3679.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!