[cqoi2016]伪光滑数 解题报告

来源:互联网 发布:2017移动互联网数据 编辑:程序博客网 时间:2024/05/16 11:18

这题有点意思。。
考虑对于i个质因子,最大的质因子至多为j能生成的数。我们需要每次在其中取最大值,显然它可以用可持久化左偏树来维护。有leftist(i,j)=leftist(i1,j)j[jin]+leftist(i,j1)
然后我们再用一个堆来维护所有可持久化左偏树的根的最小值。

= =膜拜一下大爷的做法(妈的为什么我做法总是这么傻逼!!):
左偏树的话时间复杂度当然是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;}

总结:
①一个数的质因子个数是很少的!

0 0