bzoj3679 数字之积
Posted 逢山开路 遇水架桥
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 */
以上是关于bzoj3679 数字之积的主要内容,如果未能解决你的问题,请参考以下文章