这题有点意思。。
考虑对于i个质因子,最大的质因子至多为j能生成的数。我们需要每次在其中取最大值,显然它可以用可持久化左偏树来维护。有 leftist(i,j)=leftist(i−1,j)∗j[ji≤n]+leftist(i,j−1)
然后我们再用一个堆来维护所有可持久化左偏树的根的最小值。
= =膜拜一下大爷的做法(妈的为什么我做法总是这么傻逼!!):
左偏树的话时间复杂度当然是 O(KlogK+(AlogAlogN)2)(A=128) .
但如果我们把左偏树改成暴力减小每个质因子然后全插进堆里的话。。时间复杂度是 O(KlogK∗ 质因子个数 ) ,质因子个数最大是16,实际情况应该在4~5左右。所以直接暴力即可。
#include<cstdio>
#include<iostream>
using namespace std;
#include<cstring>
#include<cmath>
#include<algorithm>
typedef long long LL;
const LL N=1e18+5;
const int K=8e5+5;
const int A=128;
const int P=35;
const int Log=60;
int prime[P];
bool p[A+5];
const int Left=1e6;
struct LS{
int ls,rs;
int dis;
LL flag;
LL data;
}leftist[Left];
int ltot=2;
int root[Log+5][P];
void out(int node){
printf("leftist[%d]={ls=%d,rs=%d,dis=%d,flag=%I64d,data=%I64d}\n",node,leftist[node].ls,leftist[node].rs,leftist[node].dis,leftist[node].flag,leftist[node].data);
}
void paint(int &node,LL flag){
if(node){
leftist[ltot]=leftist[node];
node=ltot++;
leftist[node].flag*=flag;
leftist[node].data*=flag;
}
}
void pushdown(int node){
if(leftist[node].flag!=1){
paint(leftist[node].ls,leftist[node].flag),paint(leftist[node].rs,leftist[node].flag);
leftist[node].flag=1;
}
}
void merge(int &node,int u,int v){
//printf("Merge(%d,%d)\n",u,v);
if(!u&&!v){
node=0;
return;
}
if(!u){
node=v;
return;
}
if(!v){
node=u;
return;
}
node=ltot++;
if(leftist[u].data<leftist[v].data)swap(u,v);
leftist[node]=leftist[u];
pushdown(node);
merge(leftist[node].rs,leftist[node].rs,v);
if(leftist[leftist[node].rs].dis>leftist[leftist[node].ls].dis)swap(leftist[node].ls,leftist[node].rs);
leftist[node].dis=leftist[leftist[node].rs].dis+1;
}
int heap[P*Log+K],htot=1;
void out(){
for(int i=1;i<htot;++i)printf("%d ",heap[i]);
puts("");
}
bool less_heap(int a,int b){
return leftist[heap[a]].data<leftist[heap[b]].data;
}
void down(int node){
for(int next=node<<1;next<htot;node=next,next<<=1){
if(next+1<htot&&less_heap(next,next+1))++next;
if(less_heap(next,node))return;
swap(heap[node],heap[next]);
}
}
void up(int node){
for(int next=node>>1;next&&less_heap(next,node);node=next,next>>=1)swap(heap[node],heap[next]);
}
void add(int node){
if(node){
heap[htot]=node;
up(htot++);
}
}
int main(){
freopen("bzoj_4524.in","r",stdin);
freopen("bzoj_4524.out","w",stdout);
for(int i=2;i<A;++i){
if(!p[i])prime[++prime[0]]=i;
for(int j=1;j<=prime[0]&&i*prime[j]<A;++j){
p[i*prime[j]]=1;
if(i%prime[j]==0)break;
}
}
LL n,tmp;
int k;
cin>>n>>k;
leftist[1]=(LS){0,0,1,1,1};
for(int j=0;j<=prime[0];++j)root[0][j]=1;
int u,v;
for(int j=1,i;j<=prime[0];++j){
tmp=n;
for(i=1;tmp>=prime[j];++i,tmp/=prime[j]){
u=root[i-1][j];
paint(u,prime[j]);
v=root[i][j-1];
//cout<<"("<<i<<','<<j-1<<")="<<v<<endl;
merge(root[i][j],u,v);
//printf("root(%d,%d)=",i,j);
//out(root[i][j]);
}
for(;i<=Log;++i)root[i][j]=root[i][j-1];
}
for(int i=1;i<=Log;++i)
if(root[i][prime[0]]){
//cout<<"Get("<<i<<","<<prime[0]<<")\n";
heap[htot++]=root[i][prime[0]];
}
for(int i=htot;--i;)down(i);
//out();
while(--k){
pushdown(heap[1]);
if(leftist[heap[1]].ls)add(leftist[heap[1]].ls);
if(leftist[heap[1]].rs)add(leftist[heap[1]].rs);
heap[1]=heap[--htot];
down(1);
//out();
if(htot==1){
puts("No answer");
return 0;
}
}
cout<<leftist[heap[1]].data<<endl;
}
总结:
①一个数的质因子个数是很少的!