• [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]表示当前算到第i位,乘积下标为j,到目前为止是否大于n。转移时要二分乘积的位置,所以复杂度是位数*乘积个数*log乘积个数*2

    注:stl是个好东西啊,unique真方便~

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    #include<iostream>
    #include<string>
    #include<ctime>
    #include<queue>
    #include<map>
    #include<set>
    #include<vector>
    #define LL long long
    using namespace std;
    const int N=400010,mod=1e9+7;
    struct node
    {
        int x,y; LL z;
        bool operator < (const node &x) const{return z<x.z;}
    };
    priority_queue<node>q;
    LL n,f[15][N][2],g[N],a[N];
    int k,cnt,num[15],len;
    LL read() {LL d=0,f=1; char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') d=(d<<3)+(d<<1)+c-48,c=getchar(); return d*f;}
    void judge(){freopen(".in","r",stdin); freopen(".out","w",stdout);}
    void dfs(int k,int l,LL now)
    {
        if (l>len) {a[++cnt]=now; return;}
        for (int i=k;i<10;i++) dfs(i,l+1,now*i);
    }
    bool cmp(LL a,LL b){return a>b;}
    node make(int x,int y)
    {
        node res;
        res.x=x; res.y=y; res.z=g[x]*g[y];
        return res;
    }
    int main()
    {
        //judge();
        n=read(); k=read();
        for (;n;n/=10) num[++len]=n%10;
        a[cnt=1]=0;
        dfs(1,1,1);
        sort(a+1,a+1+cnt);
        cnt=unique(a+1,a+1+cnt)-a-1;
        f[0][2][0]=1;
        for (int i=0;i<=len;i++)
            for (int j=1;j<=cnt;j++)
                for (int k=0;k<=1;k++) if (f[i][j][k])
                    for (int l=i?1:0;l<10;l++)
                    {
                        int pjy=lower_bound(a+1,a+1+cnt,a[j]*l)-a;
                        f[i+1][pjy][k+l>num[i+1]]+=f[i][j][k];
                    }
        for (int i=1;i<=cnt;i++)
        {
            for (int j=1;j<len;j++) g[i]+=f[j][i][0]+f[j][i][1];
            g[i]+=f[len][i][0];
        }
        sort(g+1,g+1+cnt,cmp);
        LL ans=0;
        q.push(make(2,2));
        while (!q.empty())
        {
            node ljj=q.top(); q.pop();
            ans=(ans+ljj.z)%mod;
            if (--k==0) break;
            if (ljj.x!=ljj.y)
            {
                ans=(ans+ljj.z)%mod;
                if (--k==0) break;
                q.push(make(ljj.x+1,ljj.y));
            }
            if (ljj.x==2) q.push(make(ljj.x,ljj.y+1));
        }
        printf("%d",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    NET与J2EE比拼
    NET与J2EE比拼
    Linux下添加FTP账号和服务器、增加密码和用户,更改FTP目录
    PS去除图片中文字的方法详细图文教程
    VC下绘图程序Demo
    U盘(auto病毒)类病毒分析与解决方案
    数据库技术源代码
    多边形填充实验
    错误总结1,动态加载部分不能显示的原因
    android实现开机欢迎界面
  • 原文地址:https://www.cnblogs.com/lujiaju6555/p/6718410.html
Copyright © 2020-2023  润新知