zoukankan      html  css  js  c++  java
  • bzoj3679 数字之积

    传送门: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
  • 相关阅读:
    myeclipse自带客户端连接mysql数据库
    javaweb学习总结八(xml约束DTD)
    javaweb学习总结七(XML语言作用、语法)
    javaweb学习总结六(泛型)
    plsql常用快捷键
    javaweb学习总结五(内省、beanUtils工具包)
    javaweb学习总结四(反射技术)
    javaweb学习总结三(枚举)
    eclipse常用快捷键汇总
    plsql设置窗口默认格式
  • 原文地址:https://www.cnblogs.com/galaxies/p/bzoj3679.html
Copyright © 2011-2022 走看看