Bzoj 3131 [Sdoi2013]淘金 题解

Posted Hzoi_joker

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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\n",sum);
128     return 0;
129 }
View Code

 












以上是关于Bzoj 3131 [Sdoi2013]淘金 题解的主要内容,如果未能解决你的问题,请参考以下文章

bzoj3131 [Sdoi2013]淘金

BZOJ 3131 SDOI2013 淘金 数位dp

bzoj千题计划268:bzoj3131: [Sdoi2013]淘金

淘金(bzoj 3131)

BZOJ 3131 淘金

Bzoj 3124: [Sdoi2013]直径 题解