1. 程式人生 > >BZOJ 3131 SDOI2013 淘金 數位dp

BZOJ 3131 SDOI2013 淘金 數位dp

AI 不難 amp 優先隊列 OS 正方 範圍 解決 names

原題鏈接: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