zoukankan      html  css  js  c++  java
  • Bzoj 3131 [Sdoi2013]淘金 题解

    3131: [Sdoi2013]淘金

    Time Limit: 30 Sec  Memory Limit: 256 MB
    Submit: 733  Solved: 363
    [Submit][Status][Discuss]

    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

      久违的的数位DP题……
      首先,我们可以发现横纵坐标没有任何关系,完全独立,所以我们真正要做的是求出每个数有多少个数以他为f值。按照套路我们还是应该先dfs一下各种可能的乘积,然后弱到一定地步的我就懵了,乘积得多少种啊,存都存不下,然后事实证明我错了,实践证明我只要打一下表就会发现其实只有八千多个乘积……
      求出来所有乘积之后我们接着按照数位DP的套路搞。不过为了方便,我们把我们得到的所有乘积先去重和离散。设f[i][j][k]为当前我们算到第i位,第i位为j,当前乘积离散后为k的方案数。转移也是很好转移的,直接枚举那一位的数是几就好了。统计答案的时候也是按照套路,先统计位数比n低的,然后将位数从高到低依次统计每一个k答案即可。至于答案。我们用优先队列排序就可以了。
      1 #include <iostream>
      2 #include <cstdlib>
      3 #include <cstdio>
      4 #include <cstring>
      5 #include <algorithm>
      6 #include <cmath>
      7 #include <queue>
      8 #include <map>
      9 #include <set>
     10 #include <vector>
     11 #define N 10005
     12 using namespace std;
     13 long long n;
     14 int k,zz,cnt;
     15 long long c[50],p=1000000007;
     16 long long jg[1000005];
     17 void dfs(long long x,int st,int len)
     18 {
     19     if(len==14)
     20     {
     21         return;
     22     }
     23     zz++;
     24     jg[zz]=x;
     25     for(int i=st;i<=9;i++)
     26     {
     27         dfs(x*i*1ll,i,len+1);
     28     }
     29 }
     30 long long f[15][10][N];
     31 long long ans[N];
     32 long long work(int x)
     33 {
     34     long long sum=0;
     35     for(int i=1;i<cnt;i++)
     36     {
     37         for(int j=1;j<=9;j++)
     38         {
     39             sum+=f[i][j][x];
     40         }
     41     }
     42     long long la=1;
     43     for(int i=cnt;i>0;i--)
     44     {
     45         if(la==0||jg[x]%la||la>jg[x])break;
     46         int t=lower_bound(jg+1,jg+1+zz,jg[x]/la)-jg;
     47         for(int j=1;j<c[i];j++)
     48         {
     49             sum+=f[i][j][t];
     50         }
     51         la*=c[i];
     52     }
     53     return sum;
     54 }
     55 map<int,bool> vi[N];
     56 struct no{
     57     int a,b;
     58     long long data;
     59     bool friend operator < (no a,no b)
     60     {
     61         return a.data<b.data;
     62     }
     63 };
     64 int main()
     65 {
     66     scanf("%lld%d",&n,&k);
     67     zz++;jg[zz]=0;
     68     long long tt=n;
     69     while(tt)
     70     {
     71         cnt++;
     72         c[cnt]=tt%10;
     73         tt/=10;
     74     }
     75     c[1]++;
     76     dfs(1,2,1);
     77      
     78     sort(jg+1,jg+zz+1);
     79     zz=unique(jg+1,jg+zz+1)-jg-1;
     80     for(int i=1;i<=9;i++)
     81     {
     82         f[1][i][lower_bound(jg+1,jg+zz+1,i)-jg]=1;
     83     }
     84     for(int i=1;i<cnt;i++)
     85     {
     86         for(int j=1;j<=9;j++)
     87         {
     88             for(int k=1;k<=9;k++)
     89             {
     90                 for(int l=1;l<=zz;l++)
     91                 {
     92                     if(!f[i][j][l])continue;
     93                     if(jg[l]*(long long)k>jg[zz])continue;
     94                     f[i+1][k][lower_bound(jg+1,jg+1+zz,jg[l]*k)-jg]+=f[i][j][l];
     95                 }
     96             }
     97         }
     98     }
     99     for(int i=1;i<=zz;i++)
    100     {
    101         ans[i]=work(i);
    102     }
    103     sort(ans+1,ans+zz+1);
    104      
    105     no aa;
    106     aa.a=aa.b=zz;
    107     aa.data=ans[zz]*ans[zz];
    108     priority_queue<no> q1;
    109      
    110     q1.push(aa);
    111     long long sum=0;
    112     while(k&&!q1.empty())
    113     {
    114         k--;
    115         while(!q1.empty()&&vi[q1.top().a][q1.top().b]) q1.pop();
    116         aa=q1.top();q1.pop();
    117         sum+=aa.data%p;
    118         sum%=p;
    119         vi[aa.a][aa.b]=1;
    120         aa.a--;
    121         aa.data=ans[aa.a]*ans[aa.b];
    122         q1.push(aa);
    123         aa.a++;aa.b--;
    124         aa.data=ans[aa.a]*ans[aa.b];
    125         q1.push(aa);
    126     }
    127     printf("%lld
    ",sum);
    128     return 0;
    129 }
    View Code
  • 相关阅读:
    目录
    mysql 常用命令复习
    mysql备份及pymysql
    mysql 表操作
    mysql 库操作
    mysql 数据库
    各种推导式
    python 之I/O模型
    python 之进程
    python之 多线程(二)
  • 原文地址:https://www.cnblogs.com/liutianrui/p/7780399.html
Copyright © 2011-2022 走看看