3131: [Sdoi2013]淘金


Time Limit: 30 Sec  Memory Limit: 256 MB
Submit: 847  Solved: 423
[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


 

Sample Output



HINT


N < = 10^12 ,K < = 100000

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

题解:


发现题目变成了scoi2012某道题简化版。

可以很轻松愉快的发现如果是各位数字相乘,质因子只有2357,又限制最多只有12位,所以发现预处理出来可以得到数就一万多个。

于是我们就轻松愉快的处理出了,g[i][j],i位数乘积为j的数出现次数。

j很大,但数只有一万多个,hash走起。

好,数位dp转移也很明显了,不想太讲太多,f[i][j]   i位数内乘积为j的数出现次数。。

好了,发现转移完毕后我们要找所有数次数相乘的前k大。

暴力枚举所有数是10000^2的。

我们发现每个数都是从第一个数转移起走,那么我们对于10000多个数把它记录成三元组(i,j,k)当前价值为i,当前数位j,匹配数位k,每次选了当前三元组后

又加入(v[j] * v[k + 1],j,k + 1)放入优先队列即可

AC代码:


# include <iostream>
# include <cstdio>
# include <queue>
# include <algorithm>
using namespace std;
typedef long long LL;
const int N = 5e4 + ;
const int M = 2e5 + ;
const LL mod = 1e9 + ;
LL g[][N],state[N],s[N],n,K;int dt,hs[M],data[],len;
struct node{
LL val;int id;
bool operator <(const node & other)const{return val > other.val;}
}a[N];
struct e{
LL w;int id,Id;
bool operator <(const e & other)const{return w < other.w;}
};
priority_queue<e>st;
void insert(LL s)
{
int p = s % M;
while(hs[p])
{
if(state[hs[p]] == s)return;
p++;
if(p == M)p = ;
}
hs[p] = ++dt;state[hs[p]] = s;
}
int id(LL s)
{
int p = s % M;
while(hs[p])
{
if(state[hs[p]] == s)return hs[p];
p++;
if(p == M)p = ;
}
return ;
}
void init()
{
for(int i = ;i <= ;i++)
{
insert(i);
g[][id(i)] = ;
}
for(int i = ;i <= ;i++)
{
int tmp = dt;
for(int j = ;j <= tmp;j++)
{
LL x = state[j];int v = j,u;
for(LL k = ;k <= ;k++)
{
insert(x * k);
u = id(x * k);
g[i + ][u] += g[i][v];
}
}
}
}
LL dfs(int now,LL K,bool lim,bool first)
{
if(!now)return K == && !first;
if(!lim && !first)return g[now][id(K)];
LL ret = ;int p = lim ? data[now] : ;
if(first)ret += dfs(now - ,K,false,first);
for(LL i = ;i <= p;i++)if(!(K % i))
ret += dfs(now - ,K / i,lim && i == p,false);
return ret;
}
void calc(LL k)
{
len = ;
while(k)data[++len] = k % ,k /= ;
for(int i = ;i <= dt;i++)a[i] = (node){dfs(len,state[i],true,true),i};
sort(a + ,a + dt + );
for(int i = ;i <= dt;i++)if(a[i].val)
st.push((e){a[i].val * a[].val,i,});
}
int main()
{
init();
scanf("%lld %lld",&n,&K);
calc(n);LL ans = ,ret;int u,v;
while(K && !st.empty())
{
(ans += st.top().w) %= mod;u = st.top().id;v = st.top().Id + ;
st.pop();
if(!a[v].val)continue;
st.push((e){a[u].val * a[v].val,u,v});
K--;
}
printf("%lld\n",ans);
}

[Bzoj3131][Sdoi2013]淘金(数位dp)(优先队列)的更多相关文章

  1. [SDOI2013]淘金 数位DP

    做了好久.... 大致思路: 求出前k大的方格之和即为答案, 先考虑一维的情况,设f[i]为数位上各个数相乘为i的数的总数,也就是对于数i,有f[i]个数它们各个位相乘为i, 再拓展到二维,根据乘法原 ...

  2. BZOJ 3131 [SDOI2013]淘金 - 数位DP

    传送门 Solution 这道数位$DP$看的我很懵逼啊... 首先我们肯定要先预处理出 $12$位乘起来的所有的可能情况, 记录入数组 $b$, 发现个数并不多, 仅$1e4$不到. 然后我们考虑算 ...

  3. bozoj3131: [Sdoi2013]淘金 数位dp

    链接 https://www.lydsy.com/JudgeOnline/problem.php?id=3131 思路 1. 函数值的素因子只有2.3.5.7 由他们组成的状态不多,爆搜的时候即使搜不 ...

  4. bzoj 3131 [Sdoi2013]淘金(数位DP+优先队列)

    Description 小Z在玩一个叫做<淘金者>的游戏.游戏的世界是一个二维坐标.X轴.Y轴坐标范围均为1..N.初始的时候,所有的整数坐标点上均有一块金子,共N*N块.    一阵风吹 ...

  5. [BZOJ3131] [Sdoi2013]淘金

    [BZOJ3131] [Sdoi2013]淘金 Description 小Z在玩一个叫做<淘金者>的游戏.游戏的世界是一个二维坐标.X轴.Y轴坐标范围均为1..N.初始的时候,所有的整数坐 ...

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

    http://www.lydsy.com/JudgeOnline/problem.php?id=3131 如果已知 s[i]=j 表示有j个<=n数的数码乘积=i 那么就会有 s[a1]*s[a ...

  7. 【数位dp】bzoj3131: [Sdoi2013]淘金

    思路比较自然,但我要是考场上写估计会写挂:好像被什么不得了的细节苟住了?…… Description 小Z在玩一个叫做<淘金者>的游戏.游戏的世界是一个二维坐标.X轴.Y轴坐标范围均为1. ...

  8. [您有新的未分配科技点]数位DP:从板子到基础(例题 bzoj1026 windy数 bzoj3131 淘金)

    只会统计数位个数或者某种”符合简单规律”的数并不够……我们需要更多的套路和应用 数位dp中常用的思想是“分类讨论”思想.下面我们就看一道典型的分类讨论例题 1026: [SCOI2009]windy数 ...

  9. bzoj 3131 [Sdoi2013]淘金(数位dp)

    题目描述 小Z在玩一个叫做<淘金者>的游戏.游戏的世界是一个二维坐标.X轴.Y轴坐标范围均为1..N.初始的时候,所有的整数坐标点上均有一块金子,共N*N块. 一阵风吹过,金子的位置发生了 ...

随机推荐

  1. 一个简单的139邮箱登录脚本--->java-selenium

    import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebE ...

  2. vs2010 在函数级别设置优化

    平时开发的时候,为了方便调试,visual studio 的Configuration 设置成Release. 同时为了事后调试,Optimization总是设置成Disabled.这样做是方便查看变 ...

  3. raid 0 1 5 10 总结的知识点

    raid 0 1 5 10 raid 发的别名条带 raid 0 读取性能最高需要磁盘2*N个(N>0)代表所有raid级别中的最高存储性能,其实原理就是把连续的数据分散到多个磁盘上存取,这样, ...

  4. 线性判别分析(LDA)

    降维的作用: 高维数据特征个数多,特征样本多,维度也很大,计算量就会很大,调参和最后评估任务时,计算量非常大,导致效率低. 高位数据特征特别多,有的特征很重要,有的特征不重要,可以通过降维保留最好.最 ...

  5. 【搜索】P1019 单词接龙

    题目描述 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合 ...

  6. poj3710 Christmas Game

    题目描述 题解: 树上删边. 对于奇数长度的环,可以看做一条边. 对于偶数长度的环,可以看做什么都没有. 没有特别好的解释…… 代码: #include<cstdio> #include& ...

  7. new命令的原理

    function Person(name, age) { this.name = name; this.age = age } var person = new Person('小明', 18); c ...

  8. Python旅途——函数(1)

    函数 简介 到目前为止,我们一直所接触的都是属于面向过程编程,这样的代码会降低代码的可读性,因此引入了函数式编程,在后面我们还会学到面向对象编程. 函数式编程 函数本质:将N行代码拿到别处,并给他起个 ...

  9. POJ 1236 Network of Schools (强连通分量缩点求度数)

    题意: 求一个有向图中: (1)要选几个点才能把的点走遍 (2)要添加多少条边使得整个图强联通 分析: 对于问题1, 我们只要求出缩点后的图有多少个入度为0的scc就好, 因为有入度的scc可以从其他 ...

  10. MongoDB中WiredTiger的数据可用性设置

    此文已由作者温正湖授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. MongoDB中WiredTiger的参数配置主要通过 wiredtiger_open (http://so ...