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

 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 }
View Code

猜你喜欢

转载自www.cnblogs.com/cychester/p/9642528.html