先把质数都筛进数组p。
我们设f[i,j]表示分解后最大质数为p[i],分解的结果是j项的数的集合。
为了顺利的推出f[i,j]我们还要设g[i,j]表示f的前缀和。
先让我们重定义一些符号:
1、a+b返回集合a与集合b的并(a与b均为集合)
2、a*b表示集合a内所有数乘上b(a为集合,b为一个数)
那么转移是这样的:
f[i,j]=∑jk=1g[i−1,j−k]∗p[i]k
g[i,j]=g[i−1,j]+f[i,j]
那么这个集合是什么呢?当然就是可持久化可并堆啦!
有一种显然的做法,那就是设一个集合ans,表示所有符合条件的f的和。
然后就在ans中弹k-1个出来就好了。
然后这样做所需空间很大,会崩。
其实我们只需要把符合条件的f对应的堆顶扔进一个大堆中,大堆按照结点的值,大的游戏。
然后同样是在大堆里弹k-1个。
如果这样做空间还是挂了,请参考代码以及置顶的好东西里面关于可持久化的一些内容。
枚举状态其实只要这样就好
fo(i,1,top){
fo(j,1,floor(log(n)/log(p[i])))
#include<cstdio>
#include<algorithm>
#include<set>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int maxn=18000000+10;
int dis[maxn],left[maxn],right[maxn],p[50];
ll key[maxn],mul[maxn];
int f[200][100],g[200][100];
bool bz[200];
int i,j,k,l,t,m,tot,top;
ll n;
struct dong{
int id;
dong(int x){id=x;}
};
bool operator <(dong a,dong b){
return key[a.id]>key[b.id]||key[a.id]==key[b.id]&&a.id<b.id;
}
multiset<dong> ans;
void make_list(){
fo(i,2,127)
if (!bz[i])
fo(j,2,127/i)
bz[i*j]=1;
fo(i,2,127){
if (i>n) break;
if (!bz[i]) p[++top]=i;
}
}
ll qsm(int x,int y){
if (!y) return 1;
ll t=qsm(x,y/2);
t=t*t;
if (y%2) t=(ll)t*x;
return t;
}
int newnode(int x){
if (!x) return 0;
int t=++tot;
left[t]=left[x];
right[t]=right[x];
dis[t]=dis[x];
key[t]=key[x];
mul[t]=mul[x];
return t;
}
int mark(int x,ll y){
int t=newnode(x);
key[t]*=y;
mul[t]*=y;
return t;
}
void down(int x){
if (mul[x]>1){
left[x]=mark(left[x],mul[x]);
right[x]=mark(right[x],mul[x]);
mul[x]=1;
}
}
int merge(int a,int b){
if (!a) return newnode(b);
if (!b) return newnode(a);
down(a);down(b);
if (key[a]<key[b]) swap(a,b);
int t=newnode(a);
right[t]=merge(right[a],b);
if (dis[right[t]]>dis[left[t]]) swap(left[t],right[t]);
dis[t]=dis[right[t]]+1;
return t;
}
int deletemin(int x){
down(x);
return merge(left[x],right[x]);
}
int main(){
scanf("%lld%d",&n,&m);
make_list();
g[0][0]=f[0][0]=dis[1]=key[1]=mul[1]=tot=1;
fo(i,1,top){
fo(j,1,floor(log(n)/log(p[i]))){
fo(k,1,j){
t=mark(g[i-1][j-k],qsm(p[i],k));
f[i][j]=merge(f[i][j],t);
}
ans.insert(dong(f[i][j]));
g[i][j]=merge(g[i-1][j],f[i][j]);
}
g[i][0]=g[i-1][0];
}
m--;
while (m--){
t=(*ans.begin()).id;
ans.erase(ans.begin());
ans.insert(dong(merge(left[t],right[t])));
}
printf("%lld\n",key[(*ans.begin()).id]);
}