[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;
}