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 }