BZOJ 3131 淘金

考虑到乘出来的东西实际上不多。。。直接map记下。

然后比如说x位的计数,就把ceil(x/2)和trunc(x/2)的情况乘起来。

然后就是一个ai,j=tab[i]*tab[j],求这个数表前k大的问题。

这个可以排序,然后单调队列,把状态慢慢往后推就行了。(注意到ai,j都不用取模才可以这么做,否则。。。我也不知道怎么做)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<cmath>
#define maxn 1000050
#define mod 1000000007
using namespace std;
long long n,k,bit[20],ret=0,a[maxn],tot=0;
long long ans=0;
map <long long,long long> tab[7],mp;
map <pair<long long,long long>,long long> vis;
map <long long,long long>::iterator it1,it2;
struct status
{
    long long p1,p2;
    long long val;
    status (long long p1,long long p2,long long val):p1(p1),p2(p2),val(val) {}
    status () {}
    friend bool operator < (const status &x,const status &y)
    {
        return x.val<y.val;
    }
};
priority_queue <status> q;
bool cmp(long long x,long long y) {return x>y;}
void pre_dfs(long long now,long long ret)
{
    if (now-1) tab[now-1][ret]++;
    if (now==7) return;
    for (long long i=1;i<=9;i++) pre_dfs(now+1,ret*i);
}
void get_bit(long long x)
{
    ret=0;
    while (x) {bit[++ret]=x%10;x/=10;}
}
void update(long long ret,long long x)
{
    if (!x) {mp[ret]++;return;}
    if (!(x-1)) {for (long long i=1;i<=9;i++) mp[ret*i]++;return;}
    long long l=ceil((double)x/2),r=trunc((double)x/2);
    for (it1=tab[l].begin();it1!=tab[l].end();it1++)
        for (it2=tab[r].begin();it2!=tab[r].end();it2++)
            mp[ret*(it1->first)*(it2->first)]+=it1->second*it2->second;
}
void digit_dp()
{
    for (long long i=1;i<=ret-1;i++)
        update(1,i);
    long long rets=1;
    for (long long i=ret;i>=1;i--)
    {
        for (long long j=1;j<bit[i];j++)
            update(rets*j,i-1);
        rets*=bit[i];
    }
    mp[rets]++;
}
int main()
{
    scanf("%lld%lld",&n,&k);
    pre_dfs(1,1);
    get_bit(n);
    digit_dp();
    for (it1=mp.begin();it1!=mp.end();it1++)
    {
        if (!it1->first) continue;
        a[++tot]=it1->second;
    }
    sort(a+1,a+tot+1,cmp);
    q.push(status(1,1,(long long)a[1]*a[1]));
    long long tr=0;
    for (long long i=1;i<=k;i++)
    {
        tr++;
        status now=q.top();q.pop();
        if (vis[make_pair(now.p1,now.p2)]) {i--;continue;}
        ans=(ans+now.val%mod)%mod;vis[make_pair(now.p1,now.p2)]=1;
        q.push(status(now.p1,now.p2+1,(long long)a[now.p1]*a[now.p2+1]));
        q.push(status(now.p1+1,now.p2,(long long)a[now.p1+1]*a[now.p2]));
    }
    printf("%lld\n",ans%mod);
    return 0;
}
时间: 2024-07-28 13:35:04

BZOJ 3131 淘金的相关文章

Bzoj 3131 [Sdoi2013]淘金 题解

3131: [Sdoi2013]淘金 Time Limit: 30 Sec  Memory Limit: 256 MBSubmit: 733  Solved: 363[Submit][Status][Discuss] Description 小Z在玩一个叫做<淘金者>的游戏.游戏的世界是一个二维坐标.X轴.Y轴坐标范围均为1..N.初始的时候,所有的整数坐标点上均有一块金子,共N*N块.    一阵风吹过,金子的位置发生了一些变化.细心的小Z发现,初始在(i,j)坐标处的金子会变到(f(i),

[BZOJ 3131][Sdoi2013]淘金

题目连接:http://www.lydsy.com/JudgeOnline/problem.php?id=3131 首先可以想到先算出一维的,再拓展到二维. 我们设g[i]表示各位数字乘积为i的数字个数(<=n),然后可以用堆/优先队列算出二维的前k大. 现在关键是如何求g[i]. 我一开始也不会~\(≧▽≦)/~啦啦啦,但实际上所有乘积总个数只有2e5多(我也不知道为什么有题解说是1e4...可能是我错了吧),将乘积离散化,然后就可以进行数位DP了.具体如下:设f[i][j][k]表示当前算到

BZOJ 3131 SDOI2013 淘金 数位dp

原题链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3131 题意没什么好概述的..... 首先从题目对数的每一位进行相乘的操作以及N的范围可以看出来估计和数位dp有关系. 先考虑一维的情况.可以发现一个数的每一位相乘得到的数字质因数只有2,3,5,7,并且带有0的数字是没有贡献的,同时我们可以简单证明对于题目中的函数f(x)一定有f(x)<x,也即是说所有的f(x)都是在向1靠拢,具体到哪里取决于这个数的质因数. 于是可以令f(i,a,b,

淘金(bzoj 3131)

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的范围内,我们认为这块金子已经被移出游戏.同时可以发现,对于变化之后的游戏局面,

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

http://www.lydsy.com/JudgeOnline/problem.php?id=3131 如果已知 s[i]=j 表示有j个<=n数的数码乘积=i 那么就会有 s[a1]*s[a2] 个数 在一阵风之后到(a1,a2)位置 把所有的j用一个数组b存起来,从大到小排序开始把(1,1)存入堆,表示当前最多的是b[1]*b[1]每次取出堆顶(i,j),累加 b[i]*b[j],存入(i+1,j),(i,j+1),map 判重 就可以解决前k大之和的问题 i的上限是n,存不下,怎么办 我

BZOJ 1013: [JSOI2008]球形空间产生器sphere

二次联通门 : BZOJ 1013: [JSOI2008]球形空间产生器sphere /* BZOJ 1013: [JSOI2008]球形空间产生器sphere 高斯消元 QAQ SB的我也能终于能秒题了啊 设球心的坐标为(x,y,z...) 那么就可以列n+1个方程,化化式子高斯消元即可 */ #include <cstdio> #include <iostream> #include <cstring> #define rg register #define Max

bzoj 3309 DZY Loves Math - 莫比乌斯反演 - 线性筛

对于正整数n,定义f(n)为n所含质因子的最大幂指数.例如f(1960)=f(2^3 * 5^1 * 7^2)=3, f(10007)=1, f(1)=0. 给定正整数a,b,求sigma(sigma(f(gcd(i,j)))) (i=1..a, j=1..b). Input 第一行一个数T,表示询问数. 接下来T行,每行两个数a,b,表示一个询问. Output 对于每一个询问,输出一行一个非负整数作为回答. Sample Input 4 7558588 9653114 6514903 445

【BZOJ】[HNOI2009]有趣的数列

[算法]Catalan数 [题解] 学了卡特兰数就会啦>_<! 因为奇偶各自递增,所以确定了奇偶各自的数字后排列唯一. 那么就是给2n个数分奇偶了,是不是有点像入栈出栈序呢. 将做偶数标为-1,做奇数标为+1,显然当偶数多于奇数时不合法,因为它压不住后面的奇数. 然后其实这种题目,打表就可知啦--QAQ 然后问题就是求1/(n+1)*C(2n,n)%p了,p不一定是素数. 参考bzoj礼物的解法. 看到网上清一色的素数筛+分解质因数解法,不解了好久,感觉写了假的礼物-- 后来觉得礼物的做法才比

洛谷 P2709 BZOJ 3781 小B的询问

题目描述 小B有一个序列,包含N个1~K之间的整数.他一共有M个询问,每个询问给定一个区间[L..R],求Sigma(c(i)^2)的值,其中i的值从1到K,其中c(i)表示数字i在[L..R]中的重复次数.小B请你帮助他回答询问. 输入输出格式 输入格式: 第一行,三个整数N.M.K. 第二行,N个整数,表示小B的序列. 接下来的M行,每行两个整数L.R. 输出格式: M行,每行一个整数,其中第i行的整数表示第i个询问的答案. 输入输出样例 输入样例#1: 6 4 3 1 3 2 1 1 3