zoukankan      html  css  js  c++  java
  • 【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
    ",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
    ",ret);
    114 }
  • 相关阅读:
    像Google Play一样让DrawerLayout拉出的抽屉在透明系统状态栏和工具栏(ToolBar)之间。
    WebView中实现延迟加载,图片点击时才加载。
    MediaPlayer配合SurfaceView或TextureView做视频播放器时的截图方法。
    解决Fragment中使用ViewPager时,ViewPager里的Fragment错位和空白问题。
    使用SAE的Storage来为Android应用提供版本更新的检查和下载功能
    使用SAE的服务来实现android端的用户反馈功能。
    使用IntentService给自己的Android应用写一个文件下载器。
    禁止进入Activity时NumberPicker自动弹出输入法。
    使用Android系统提供的DownloadManager来下载文件。
    Android异步下载图片的类和缓存图片到SD卡的类。
  • 原文地址:https://www.cnblogs.com/Troywar/p/7651086.html
Copyright © 2011-2022 走看看