题解:[SDOI2013] 淘金
题意分析
可以发现,\(f(x)\) 有用的数值不会很多。对其进行质因数分解,则可以表述为 \(f(x)=2^i3^j5^k7^l\),不难分析得到 \(i\leq36,j\leq24,k\leq12,l\leq12\)。
求前 \(K\) 大,考虑多路归并。
设 \(a_i\) 表示有多少个 \(f(x)=i\),那么 \((i,j)\) 的贡献为 \(a_ia_j\)。多路归并就钦定 \(a_1\geq a_2\geq\cdots\) 之后,维护一个堆,设状态 \((i,j)\) 表示 \(a_i\cdot a_j\),\((i,j)\) 计入答案后,可能的新答案即 \((i+1,j),(i,j+1)\)。
接下来考虑求出 \(a_i\)。可以发现我们只需要求出所有的 \(a\) 值然后排序即可。
\(f(x)\) 不会很多,考虑数位 DP。
设状态 \(f_{x,y,i,j,k,l}\) 表示有 \(x\) 位,最高位为 \(y\),各位乘积为 \(2^i3^j5^k7^l\) 的数的数量。转移就枚举一下最高位即可,这也是为什么状态里有 \(y\),不然转移不了。
之后设 \(\displaystyle g_{x,i,j,k,l}=\sum_{y=0}^9f_{x,y,i,j,k,l}\)。
但是存在一个问题是 \(\leq n\) 的限制,考虑继续贴 \(n\) 的上界,设 \(\textit{dp}_{x,i,j,k,l}\) 为 \(n\) 以内的 \(g_{x,i,j,k,l}\) 之和,简单维护。
\(f\) 会爆空间,滚动一维即可。
AC 代码
被 zt17 称为人类勇气之赞歌。
//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
#include<set>
using namespace std;
typedef long long ll;
constexpr const int N=13,V=9,V2=36,V3=24,V5=12,V7=12,P=1e9+7,inf=0x3f3f3f3f;
ll n,L,k,f[2][V+1][V2+1][V3+1][V5+1][V7+1],dp[V2+1][V3+1][V5+1][V7+1],a[(V2+1)*(V3+1)*(V5+1)*(V7+1)+1];
ll g[N+1][V2+1][V3+1][V5+1][V7+1];
int main(){
/*freopen("test.in","r",stdin);
freopen("test.out","w",stdout);*/
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n>>k;
L=floor(log10(n))+1;
f[0][0][0][0][0][0]=1;
g[0][0][0][0][0]=1;
for(int x=1;x<=L;x++){
memset(f[x&1],0,sizeof(f[x&1]));
for(int y=1;y<=9;y++){
for(int i=0;i<=V2;i++){
for(int j=0;j<=V3;j++){
for(int k=0;k<=V5;k++){
for(int l=0;l<=V7;l++){
switch(y){
case 1:
f[x&1][y][i][j][k][l]=f[x&1^1][0][i][j][k][l];
break;
case 2:
if(i-1>=0){
f[x&1][y][i][j][k][l]+=f[x&1^1][0][i-1][j][k][l];
}
break;
case 3:
if(j-1>=0){
f[x&1][y][i][j][k][l]+=f[x&1^1][0][i][j-1][k][l];
}
break;
case 4:
if(i-2>=0){
f[x&1][y][i][j][k][l]+=f[x&1^1][0][i-2][j][k][l];
}
break;
case 5:
if(k-1>=0){
f[x&1][y][i][j][k][l]+=f[x&1^1][0][i][j][k-1][l];
}
break;
case 6:
if(i-1>=0&&j-1>=0){
f[x&1][y][i][j][k][l]+=f[x&1^1][0][i-1][j-1][k][l];
}
break;
case 7:
if(l-1>=0){
f[x&1][y][i][j][k][l]+=f[x&1^1][0][i][j][k][l-1];
}
break;
case 8:
if(i-3>=0){
f[x&1][y][i][j][k][l]+=f[x&1^1][0][i-3][j][k][l];
}
break;
case 9:
if(j-2>=0){
f[x&1][y][i][j][k][l]+=f[x&1^1][0][i][j-2][k][l];
}
break;
}
f[x&1][0][i][j][k][l]+=f[x&1][y][i][j][k][l];
g[x][i][j][k][l]+=f[x&1][y][i][j][k][l];
}
}
}
}
}
}
for(int i=0;i<=V2;i++){
for(int j=0;j<=V3;j++){
for(int k=0;k<=V5;k++){
for(int l=0;l<=V7;l++){
for(int x=1;x<L;x++){
dp[i][j][k][l]+=g[x][i][j][k][l];
}
}
}
}
}
vector<int>r;
while(n){
r.push_back(n%10);
n/=10;
}
r.push_back(inf);
reverse(r.begin(),r.end());
for(int i=0;i<=V2;i++){
for(int j=0;j<=V3;j++){
for(int k=0;k<=V5;k++){
for(int l=0;l<=V7;l++){
int i0=0,j0=0,k0=0,l0=0;
for(int x=1;x<=L;x++){
if(r[x]==0){
break;
}
for(int y=1;y<r[x];y++){
if(i-i0>=0&&j-j0>=0&&k-k0>=0&&l-l0>=0){
// dp[i][j][k][l]+=f[L-x+1][y][i-i0][j-j0][k-k0][l-l0];
switch(y){
case 1:
dp[i][j][k][l]+=g[L-x][i-i0][j-j0][k-k0][l-l0];
break;
case 2:
if(i-i0-1>=0){
dp[i][j][k][l]+=g[L-x][i-i0-1][j-j0][k-k0][l-l0];
}
break;
case 3:
if(j-j0-1>=0){
dp[i][j][k][l]+=g[L-x][i-i0][j-j0-1][k-k0][l-l0];
}
break;
case 4:
if(i-i0-2>=0){
dp[i][j][k][l]+=g[L-x][i-i0-2][j-j0][k-k0][l-l0];
}
break;
case 5:
if(k-k0-1>=0){
dp[i][j][k][l]+=g[L-x][i-i0][j-j0][k-k0-1][l-l0];
}
break;
case 6:
if(i-i0-1>=0&&j-j0-1>=0){
dp[i][j][k][l]+=g[L-x][i-i0-1][j-j0-1][k-k0][l-l0];
}
break;
case 7:
if(l-l0-1>=0){
dp[i][j][k][l]+=g[L-x][i-i0][j-j0][k-k0][l-l0-1];
}
break;
case 8:
if(i-i0-3>=0){
dp[i][j][k][l]+=g[L-x][i-i0-3][j-j0][k-k0][l-l0];
}
break;
case 9:
if(j-j0-2>=0){
dp[i][j][k][l]+=g[L-x][i-i0][j-j0-2][k-k0][l-l0];
}
break;
}
}
}
switch(r[x]){
case 1:
break;
case 2:
i0++;
break;
case 3:
j0++;
break;
case 4:
i0+=2;
break;
case 5:
k0++;
break;
case 6:
i0++,j0++;
break;
case 7:
l0++;
break;
case 8:
i0+=3;
break;
case 9:
j0+=2;
break;
}
if(x==L&&i==i0&&j==j0&&k==k0&&l==l0){
dp[i][j][k][l]++;
}
}
}
}
}
}
int cnt=0;
for(int i=0;i<=V2;i++){
for(int j=0;j<=V3;j++){
for(int k=0;k<=V5;k++){
for(int l=0;l<=V7;l++){
a[++cnt]=dp[i][j][k][l];
}
}
}
}
sort(a+1,a+cnt+1,[](ll a,ll b){
return a>b;
});
priority_queue<pair<ll,pair<int,int>>>q;
set<pair<int,int>>s;
q.push({a[1]*a[1],{1,1}});
int ans=0;
while(s.size()<k){
if(!q.size()){
break;
}
auto [value,pos]=q.top();
q.pop();
auto [i,j]=pos;
if(s.count({i,j})){
continue;
}
s.insert({i,j});
ans=(ans+value)%P;
if(j+1<=cnt){
q.push({a[i]*a[j+1],{i,j+1}});
}
if(i+1<=cnt){
q.push({a[i+1]*a[j],{i+1,j}});
}
}
cout<<ans<<'\n';
cout.flush();
/*fclose(stdin);
fclose(stdout);*/
return 0;
}

浙公网安备 33010602011771号