BZOJ 3131 SDOI2013 淘金 数位dp

Posted KKKorange的代码盒子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 3131 SDOI2013 淘金 数位dp相关的知识,希望对你有一定的参考价值。

原题链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3131

 

题意没什么好概述的。。。。。

 

首先从题目对数的每一位进行相乘的操作以及N的范围可以看出来估计和数位dp有关系。

先考虑一维的情况。可以发现一个数的每一位相乘得到的数字质因数只有2,3,5,7,并且带有0的数字是没有贡献的,同时我们可以简单证明对于题目中的函数f(x)一定有f(x)<x,也即是说所有的f(x)都是在向1靠拢,具体到哪里取决于这个数的质因数。

于是可以令f(i,a,b,c,d,0/1)表示当前考虑第i位(这次我从高到低实现的),已经考虑的数中有多少个的数位乘积为2^a * 3^b * 5^c * 7^d,有无限制。

方程很好写,注意特判一下当前位数不是N的位数的时候最高位的情况,注意初始化状态是有限制的。查找答案直接暴力扫一遍就可以了。

二维?可以发现由于这是个正方形,行列信息实际上本质是一样的,同时不难发现格子(x,y)中的金子数量最终是f(0,x的质因数分解)*f(0,y的质因数分解)。

再一想,这是个多路归并!

上一个优先队列,问题圆满解决。

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<algorithm>
 6 #include<cmath>
 7 #include<queue>
 8 #include<set>
 9 #include<map>
10 #include<vector>
11 #include<cctype>
12 using namespace std;
13 typedef unsigned long long LL;
14 const int mo=1000000007;
15 
16 LL N,K,f[15][40][27][14][14][2],A[40*27*14*14];
17 int cnt;
18 struct data{ int p1,p2; LL v; };
19 struct cmp{
20     bool operator () (data x,data y){
21         return x.v<y.v;
22     }
23 };
24 priority_queue<data,vector<data>,cmp>pq;
25 
26 void dev(int x,int *t)
27 {
28     if(!x) return;
29     while(x!=1&&x%2==0) x/=2,t[0]++;
30     while(x!=1&&x%3==0) x/=3,t[1]++;
31     while(x!=1&&x%5==0) x/=5,t[2]++;
32     while(x!=1&&x%7==0) x/=7,t[3]++;
33 }
34 void dp()
35 {
36     int up=0,n[20]={0},tt[10][4]={0}; LL tmp=N;
37     n[up++]=tmp%10,tmp/=10;
38     while(tmp) n[up++]=tmp%10,tmp/=10;
39     for(int i=0;i<10;i++) dev(i,tt[i]);
40     f[up][0][0][0][0][1]=1;
41     for(int i=up-1;i>=0;i--)
42     for(int x=1;x<10;x++){
43         int *t=tt[x];
44         for(int p1=t[0];p1<=(up-i)*3;p1++)
45         for(int p2=t[1];p2<=(up-i)*2;p2++)
46         for(int p3=t[2];p3<=up-i;p3++)
47         for(int p4=t[3];p4<=up-i;p4++){
48             f[i][p1][p2][p3][p4][0]+=f[i+1][p1-t[0]][p2-t[1]][p3-t[2]][p4-t[3]][0];
49             if(x<n[i]) f[i][p1][p2][p3][p4][0]+=f[i+1][p1-t[0]][p2-t[1]][p3-t[2]][p4-t[3]][1];
50             if(x==n[i]) f[i][p1][p2][p3][p4][1]+=f[i+1][p1-t[0]][p2-t[1]][p3-t[2]][p4-t[3]][1];
51         }
52         if(i!=up-1) f[i][t[0]][t[1]][t[2]][t[3]][0]++;
53     }
54 }
55 void work()
56 {
57     cin>>N>>K;
58     dp();
59     for(int p1=0;p1<37;p1++)
60     for(int p2=0;p2<25;p2++)
61     for(int p3=0;p3<13;p3++)
62     for(int p4=0;p4<13;p4++){
63         if(f[0][p1][p2][p3][p4][0]+f[0][p1][p2][p3][p4][1])
64             A[cnt++]=f[0][p1][p2][p3][p4][0]+f[0][p1][p2][p3][p4][1];
65     }
66     sort(A,A+cnt);
67     for(int i=0;i<cnt;i++)
68         pq.push((data){i,cnt-1,A[i]*A[cnt-1]});
69     data t;
70     int ans=0;
71     for(int k=1;k<=K;k++){
72         if(pq.empty()) break;
73         t=pq.top(); pq.pop();
74         ans=(ans+t.v%mo)%mo;
75         if(t.p2) pq.push((data){t.p1,t.p2-1,A[t.p1]*A[t.p2-1]});
76     }
77     printf("%d\n",ans);
78 }
79 int main()
80 {
81     work();
82     return 0;
83 }

 

以上是关于BZOJ 3131 SDOI2013 淘金 数位dp的主要内容,如果未能解决你的问题,请参考以下文章

bzoj3131 [Sdoi2013]淘金

[BZOJ 3131][Sdoi2013]淘金

bzoj千题计划268:bzoj3131: [Sdoi2013]淘金

淘金(bzoj 3131)

BZOJ 3131 淘金

[SDOI2013] 淘金