[bzoj3131]淘金
观察到单个坐标可能的值很少,离散化出来数位dp,然后贪心选坐标即可
- 代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n;int k;
ll pw[20];
vector<ll>nu;
map<ll,int>mp;
int TP;
inline void dfs(int nownum,int Q,ll nsum){
if(Q==12){
nu.push_back(nsum);return;
}
if(nownum<9)dfs(nownum+1,Q,nsum);
dfs(nownum,Q+1,nsum*nownum);
}
int tot;
ll cont[10000],numb[10000];
ll f[15][15][10000][2];
inline void dp(int T){//T位数字
f[T][T+1][1][pw[T]>n]=1;
for(int w=T;w;w--){
int K=(n/pw[w-1])%10;
for(int i=1;i<=9;i++)
for(int j=1;j<=tot;j++){
if(f[T][w+1][j][0]) f[T][w][mp[numb[j]*i]][0]+=f[T][w+1][j][0];
if(f[T][w+1][j][1]){
if(i<K)f[T][w][mp[numb[j]*i]][0]+=f[T][w+1][j][1];
else if(i==K)f[T][w][mp[numb[j]*i]][1]+=f[T][w+1][j][1];
}
}
}
for(int i=1;i<=tot;i++)
cont[i]+=f[T][1][i][0]+f[T][1][i][1];
}
ll s[10000];int NN;
struct pls{
int l,r;
bool operator < (const pls b)const{return s[l]*s[r] < s[b.l]*s[b.r];}
};
ll ans=0,mod=1e9+7;
priority_queue<pls>Q;
inline void ccnntt(){
sort(cont+1,cont+tot+1);
for(int i=tot;i;i--)if(cont[i])s[++NN]=cont[i];
for(int i=1;i<=NN;i++)Q.push((pls){1,i});
while(k--){
if(Q.empty())break;
pls u=Q.top();Q.pop();
ll con=s[u.l]*s[u.r]%mod;
if(u.l<NN) Q.push((pls){u.l+1,u.r});
ans=(ans+con)%mod;
}
}
int main()
{
scanf("%lld%d",&n,&k);
pw[0]=1;
for(int i=1;i<=13;i++)pw[i]=pw[i-1]*10ll;
dfs(1,0,1);
sort(nu.begin(),nu.end());
for(unsigned int i=0;i<nu.size();i++){
if(!mp[nu[i]]){ mp[nu[i]]=++tot; numb[tot]=nu[i]; }
else continue;
}
for(int i=1;i<=12;i++){
if(pw[i-1]>=n)break;
dp(i);
}
ccnntt();
printf("%lld\n",ans);
}