【bzoj 3131】[Sdoi2013]淘金

Description

小Z在玩一个叫做《淘金者》的游戏。游戏的世界是一个二维坐标。X轴、Y轴坐标范围均为1..N。初始的时候,所有的整数坐标点上均有一块金子,共N*N块。
    一阵风吹过,金子的位置发生了一些变化。细心的小Z发现,初始在(i,j)坐标处的金子会变到(f(i),fIj))坐标处。其中f(x)表示x各位数字的乘积,例如f(99)=81,f(12)=2,f(10)=0。如果金子变化后的坐标不在1..N的范围内,我们认为这块金子已经被移出游戏。同时可以发现,对于变化之后的游戏局面,某些坐标上的金子数量可能不止一块,而另外一些坐标上可能已经没有金子。这次变化之后,游戏将不会再对金子的位置和数量进行改变,玩家可以开始进行采集工作。
    小Z很懒,打算只进行K次采集。每次采集可以得到某一个坐标上的所有金子,采集之后,该坐标上的金子数变为0。
    现在小Z希望知道,对于变化之后的游戏局面,在采集次数为K的前提下,最多可以采集到多少块金子?
    答案可能很大,小Z希望得到对1000000007(10^9+7)取模之后的答案。

Input

  共一行,包含两介正整数N,K。

Output

  一个整数,表示最多可以采集到的金子数量。

Sample Input

1 2 5

Sample Output

18

HINT

N < = 10^12 ,K < = 100000

对于100%的测试数据:K < = N^2

题解:

  开始想偏了……导致整个人都是懵逼的。

  首先打个表发现,各位数字乘积不同结果大概是8000左右,然后开始乱搞。

  设$f_{i,j,k}$表示总共i位,开头数字为j,乘积排名为k的总数,转移就比较显然。

  然后枚举每个k,接下来就是基本的数位DP了,这样我们求出了某一列上每个位置的金块数量$ans_{k}$,然后画个图发现,在$(i,j)$位置上的数量为我们刚才DP出的$ans_{i}*ans_{j}$,给$ans$排个序,然后贪心即可。

代码:

  

  1 #define Troy 10/11/2017
  2 
  3 #include <bits/stdc++.h>
  4 
  5 using namespace std;
  6 
  7 typedef long long ll;
  8 
  9 const ll mod=1e9+7;
 10 
 11 inline ll read(){
 12     ll s=0,k=1;char ch=getchar();
 13     while(ch<'0'|ch>'9')    ch=='-'?k=-1:0,ch=getchar();
 14     while(ch>47&ch<='9')    s=s*10+(ch^48),ch=getchar();
 15     return s*k;
 16 }
 17 
 18 const int N=1e6;
 19 
 20 ll has[N];int num,p[20],tot;
 21 
 22 inline void dfs(ll x,int from,int step){
 23     if(step>12) return ;
 24     has[++num]=x;
 25     for(;from<10;from++){
 26         dfs(x*from,from,step+1);
 27     }
 28 }
 29 
 30 ll f[15][15][10000],n,k,ans[10000];//f[i][j][k]:i位开头为j乘积为k的答案
 31 
 32 inline void init(){
 33     has[++num]=0;    
 34     dfs(1,2,0);
 35     sort(has+1,has+num+1);    
 36     num=unique(has+1,has+num+1)-has-1;//    printf("num=%d\n",num);
 37     for(int i=1;i<=9;i++)
 38         f[1][i][lower_bound(has+1,has+num+1,i)-has]=1;
 39     for(int i=2;i<=13;i++){
 40         for(int j=1;j<10;j++){
 41             for(int k=1;k<10;k++)
 42                 for(int l=1;l<=num;l++){
 43                     if(f[i-1][k][l]==0) continue;
 44                     int x;
 45                     if(has[l]*j<=has[num]){
 46                         x=lower_bound(has+1,has+num+1,has[l]*j)-has;
 47                         f[i][j][x]+=f[i-1][k][l];
 48                     }
 49                 }
 50         }
 51     }
 52     do{    
 53         p[++tot]=n%10;
 54         n/=10;
 55     }while(n);
 56 }
 57 
 58 inline ll calc(int pos){
 59     ll ret=0;
 60     for(int i=1;i<tot;i++){
 61         for(int j=1;j<=9;j++){
 62             ret+=f[i][j][pos];
 63         }
 64     }
 65     ll last=1;
 66     for(int i=tot;i;i--){
 67         if(last>has[pos]||last==0||has[pos]%last!=0)    break;
 68         for(int j=1;j<p[i];j++){
 69             int x=lower_bound(has+1,has+1+num,has[pos]/last)-has;
 70             ret+=f[i][j][x];
 71         }
 72         last*=p[i];
 73     }
 74     return ret%mod;
 75 }
 76 
 77 bool vis[9000][9000];
 78 
 79 struct node {
 80     int pos[2];ll val;
 81     friend bool operator <(node a,node b){
 82         return a.val!=b.val?a.val<b.val:a.pos[0]!=b.pos[0]?a.pos[0]>b.pos[0]:a.pos[1]>b.pos[1];
 83     }
 84 };
 85 
 86 priority_queue<node> q;
 87 
 88 int main(){    
 89     n=read(),k=read();
 90     n++;
 91     init();    
 92     for(int i=2;i<=num;i++)
 93       ans[i]=calc(i);
 94     sort(ans+2,ans+num+1); 
 95     q.push((node){num,num,ans[num]*ans[num]});
 96     ll ret=0;
 97     while(k&&(!q.empty())){
 98         k--;
 99         node now;
100         do{
101             now=q.top();q.pop();        
102         }while(vis[now.pos[0]][now.pos[1]]&&(!q.empty()));
103         if(!vis[now.pos[0]][now.pos[1]]){
104             ret+=now.val;
105             ret%=mod;
106             if(now.pos[0]>2)
107                 q.push((node){now.pos[0]-1,now.pos[1],ans[now.pos[0]-1]*ans[now.pos[1]]});
108             if(now.pos[1]>2)
109                 q.push((node){now.pos[0],now.pos[1]-1,ans[now.pos[0]]*ans[now.pos[1]-1]});
110         }        
111         vis[now.pos[0]][now.pos[1]]=true;
112     }    
113     printf("%lld\n",ret);
114 }

 

posted @ 2017-10-11 16:03  Troywar  阅读(622)  评论(0编辑  收藏  举报