BZOJ 3131 [SDOI2013]淘金 - 数位DP
Solution
这道数位$DP$看的我很懵逼啊。。。
首先我们肯定要先预处理出 $12$位乘起来的所有的可能情况, 记录入数组 $b$, 发现个数并不多, 仅$1e4$不到。
然后我们考虑算出有多少的$x$ 使得$f(x) = y$, 并记录个数到$ans[y]$ 中。
然后? 然后我就不会啦QAQ
定义数组$f[ i ][ j ][ k ]$ , $i$ 表示 $i$位数字, $j$ 表示 所有位上的数乘起来为 $b[j]$ , $k$ 表示前 $i$ 位是否比 $N$的前$i$位大。
因为当$i = len$ 时, 是不允许比$N$大的, 所以$k$仅可能等于 $0 $
然后就有转移方程 $f[ i + 1][ nxt ][ (k + x) > a[i + 1]] += f[i][j][k]$
算出$f$ 数组后, 相应地转移进 $ans[]$中, 最后进行排序,并用大根堆维护 、 取出
Code
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<queue> 5 #include<stdlib.h> 6 using namespace std; 7 typedef long long ll; 8 9 const int N = 1e6; 10 const ll mod = 1e9 + 7; 11 12 int tot, len, a[20], k; 13 ll b[N], f[20][40000][2], ans[N], n, maxn; 14 15 struct node { 16 int x, y; ll val; 17 node(int a, int b) { 18 x = a; y = b; 19 val = ans[a] * ans[b]; 20 } 21 bool operator < (const node &b) const { 22 return val < b.val; 23 } 24 bool operator > (const node &b) const { 25 return val > b.val; 26 } 27 }; 28 29 priority_queue<node> q; 30 31 ll fpow(ll a, ll b) { 32 ll re = 1; 33 for(; b; b >>= 1, a = a * a) 34 if(b & 1) re = re * a; 35 return re; 36 } 37 38 void dfs(int dep, ll sum, int rest) { 39 b[++tot] = sum; 40 if(dep > 9) return; 41 if(!rest) return; 42 for(int i = 0; i <= rest; ++i) 43 dfs(dep + 1, sum * fpow(dep, i), rest - i); 44 } 45 46 int fd(ll x) { 47 return lower_bound(b + 1, b + 1 + tot, x) - b; 48 } 49 50 bool cmp(ll x, ll y) { 51 return x > y; 52 } 53 54 int main() 55 { 56 scanf("%lld%d", &n, &k); 57 while(n) { 58 a[++len] = n % 10; 59 n /= 10; 60 } 61 b[++tot] = 0; 62 dfs(1, 1, len); 63 sort(b + 1, b + 1 + tot); 64 tot = unique(b + 1, b + 1 + tot) - b - 1; 65 b[tot + 1] = 0x7fffffff; 66 f[0][2][0] = 1; 67 // for(int i = tot; i >= tot - 10; --i) 68 // printf("%lld\n", b[i]); 69 for(int i = 0; i <= len; ++i) 70 for(int j = 1; j <= tot; ++j) 71 for(int k = 0; k < 2; ++k) 72 if(f[i][j][k]) 73 for(int x = (i == 0)? 0 : 1; x < 10; ++x) { 74 int nxt = lower_bound(b + 1, b + 1 + tot, b[j] * x) - b; 75 f[i + 1][nxt][(k + x) > a[i + 1]] += f[i][j][k]; 76 } 77 for(int i = 1; i <= tot; ++i) { 78 for(int j = 1; j < len; ++j) 79 ans[i] += f[j][i][0] + f[j][i][1]; 80 ans[i] += f[len][i][0]; 81 } 82 sort(ans + 1, ans + 1 + tot, cmp); 83 // for(int i = 1; i <= 10; ++i) 84 // printf("%lld\n", ans[i]); 85 q.push(node(2, 2)); 86 while(!q.empty() && k) { 87 node now = q.top(); q.pop(); 88 maxn = (maxn + now.val) % mod; 89 if(!(--k)) break; 90 if(now.x != now.y) { 91 maxn = (maxn + now.val) % mod; 92 if(!(--k)) break; 93 q.push(node(now.x + 1, now.y)); 94 } 95 if(now.x == 2) q.push(node(now.x, now.y + 1)); 96 } 97 maxn = (maxn % mod + mod) % mod; 98 printf("%lld\n", maxn); 99 }