[SDOI2013]淘金

题目

爆搜毁所有,当然\(%%\)能过的\(dalao\),反正\(juruo\)那个三四十分够了

做法

\(c[i]=\sum\limits_{j} f[j]=i\),这题直接动规更简单,\(dp[i][j][0/1]\)从低到高为前\(i\)位,乘积为\(j\),是否顶着上界

My complete code

#include<bits/stdc++.h>
#include<queue>
#include<map>
using namespace std;
typedef long long LL;
const LL maxn=160100,p=1e9+7;
LL tmpl,tot,bl,n,K;
LL c[6000000],tmp[6000000],f[20][maxn][2],a[20],b[6000000];
map<LL,LL> pos;
inline void Solve(LL x){
    tot=0;
    LL Up(1);
    while(x) a[++tot]=x%10, x/=10, Up*=9;
    Up/=9; Up*=a[tot];
    tmp[tmpl=1]=1;
    for(LL i=1;i<=tot;++i){
        bl=0;
        for(LL j=1;j<=9;++j){
            for(LL k=1;k<=tmpl;++k)
                b[++bl]=tmp[k]*j;
        }
        sort(b+1,b+1+bl); bl=unique(b+1,b+1+bl)-1-b;
        tmpl=bl;
        for(LL j=1;j<=bl;++j) tmp[j]=b[j];
    }
    LL T(tmpl);
	for(LL i=1;i<=T;++i) if(tmp[i]<=Up) pos[tmp[i]]=i;else --T;
	tmpl=T;
    for(LL i=1;i<=9;++i) f[1][pos[i]][i>a[1]]=1;
    for(LL i=2;i<=tot;++i) for(LL j=1;j<=tmpl;++j) for(LL k=1;k<=9;++k){
        LL val=tmp[j];
		if(val%k!=0) continue;
        LL h=pos[val/k];
        if(k<a[i]) 
		    f[i][j][0]+=f[i-1][h][0]+f[i-1][h][1];
        else if(k>a[i])
            f[i][j][1]+=f[i-1][h][0]+f[i-1][h][1];
        else
		    f[i][j][0]+=f[i-1][h][0],
            f[i][j][1]+=f[i-1][h][1];
    }
    for(LL j=1;j<=tmpl;++j) for(LL i=1;i<=tot;++i)
        c[j]+=f[i][j][0]+(i==tot?0:f[i][j][1]);
}
struct heap{
    LL i,j;
    bool operator < (const heap &x)const{
        return c[i]*c[j]<c[x.i]*c[x.j];
    }
};priority_queue<heap> que;
int main(){
    cin>>n>>K;
    Solve(n);
    sort(c+1,c+1+tmpl);
    for(LL i=1;i<=tmpl;++i) que.push((heap){i,tmpl});
    LL ans(0);
    while(K--&&que.size()){
        heap tmp=que.top(); que.pop();
        (ans+=c[tmp.i]*c[tmp.j])%=p;
        if(tmp.j==1) continue;
        que.push((heap){tmp.i,tmp.j-1});
    }cout<<ans;
    return 0;
}
posted @ 2019-02-28 18:33  y2823774827y  阅读(148)  评论(0编辑  收藏  举报