LuoguP3303 「SDOI2013」淘金
哇简单DP题!
这都能评黑?
考虑对于每个 (x) ,求出 (f(i)=x) 的 (i) 的个数,使用数位 DP ,由于 (x) 的质因子只可能有 2,3,5,7 四种,所以 (x) 的范围不会太大,数位 DP 记录已用格子数和每个质因子的指数即可。记其为 (c(x)) 。
然后对 (c(x)) 从大到小排序,对每个点记录指针表示最大的可用点,用堆维护即可。
#include<bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fd(i,a,b) for(int i=a;i>=b;--i)
#include <ext/pb_ds/priority_queue.hpp>
using namespace __gnu_pbds;
#define ll long long
using namespace std;
const int N=1e5+10;
const int M=5e6+10;
const int mod=1e9+7;
ll n,f[20][41][30][20][20],c[M],ans;
int k,a[20],s1,s2,s3,s4,cnt;
bool flag=0;
struct node{
ll x,y;
inline bool operator<(const node &o)const{
return x * c[y] < o.x * c[o.y];
}
};
__gnu_pbds ::priority_queue< node > d;
bool cmp(ll a,ll b){return a>b;}
void add(ll &a,ll b){a=(a+b>=mod?a+b-mod:a+b);}
void trans(int t,int S1,int S2,int S3,int S4,int num,ll s,int type=1){
while(!(num%2))++S1,num/=2;
while(!(num%3))++S2,num/=3;
while(!(num%5))++S3,num/=5;
while(!(num%7))++S4,num/=7;
if(type==-1){
s1=S1;s2=S2;s3=S3;s4=S4;
return;
}
f[t][S1][S2][S3][S4]+=s;
}
void dp(){
int m=0;
for(ll i=n;i;i/=10)a[++m]=i%10;
fo(i,1,a[m]-1)trans(m,0,0,0,0,i,1);
flag|=(a[m]==0);
if(!flag)trans(m,0,0,0,0,a[m],1,-1);
fd(i,m-1,1){
fo(j1,0,39){
fo(j2,0,25){
fo(j3,0,17){
fo(j4,0,14){
ll tmp=f[i+1][j1][j2][j3][j4];
if(!tmp)continue;
fo(l,1,9){
trans(i,j1,j2,j3,j4,l,tmp);
}
}
}
}
}
fo(l,1,9)
trans(i,0,0,0,0,l,1);
if(!flag)
fo(l,1,a[i]-1)
trans(i,s1,s2,s3,s4,l,1);
flag|=(a[i]==0);
if(!flag)trans(1,s1,s2,s3,s4,a[i],1,-1);
}
if(!flag)trans(1,s1,s2,s3,s4,1,1);
fo(j1,0,39){
fo(j2,0,25){
fo(j3,0,17){
fo(j4,0,14){
ll tmp=f[1][j1][j2][j3][j4];
if(tmp){
c[++cnt]=tmp;
}
}
}
}
}
}
void solve(){
sort(c+1,c+cnt+1,cmp);
// fo(i,1,cnt)printf("%d ",c[i]);
// printf("
");
fo(i,1,cnt)
d.push((node){c[i],1});
k=min((ll)k,(ll)cnt*cnt);
fo(i,1,k){
node a=d.top();
d.pop();
add(ans,a.x * c[a.y] % mod);
if(a.y<cnt){
d.push((node){a.x,a.y+1});
}
}
}
int main(){
scanf("%lld%d",&n,&k);
dp();
solve();
printf("%lld
",ans);
return 0;
}