您的位置:首页 > 其它

BZOJ4524 [CQOI2016]伪光滑数 可持久化可并堆+DP

2016-04-12 12:52 330 查看


很有意思的一个题

考场上我竟然乱搞出这种奇怪的以前想都没想过的算法(以前根本想不到函数式数据结构还可以拿来DP)

其实写这个题解我也是不想这个有趣的方法就这么绝迹了呢。。。

因为是求第K大所以不难想到用堆的K路归并问题,对答案的种类我们分类,最直观的分类就是按最大因子和分解项数来分类

即用f[i,j]表示最大质因子为p[i],用了j项分解数的数的集合,因为要求数的不重不漏,我们力求让所有的数都由互素的小数集合扩展得到,为了获得之前所有的数,我们保存g[i,j]为f[i,j]的前缀和,意为前i种素因子的所有数集,不难得到DP方程:



其中加号是集合的并,只要这些集合可以归并、求最大值,就可以在外层用堆维护每个集合的最大值,每次取最大的一个,删除最大值,还可以对集合进行乘法,而这一些需求均满足可并堆的性质,因此我们用可持久化可并堆来作为数值,进行DP。

可并堆的乘法用标记实现,标记下传时新建节点即可。注意中间过程可能爆long long,乘法要判>0防炸。

#include<queue>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
struct node{
int i,k;LL v;
node(int a,int b,LL c){i=a;k=b;v=c;}
bool operator<(node b)const{return v<b.v;}
};
priority_queue<node>q;
struct Heap{LL v,tg;int l,r;}c[16000005];
LL N;
int K,tot=0,p[505],vst[505],f[505][505],g[505][505];
int NewNode(int x,LL tg){
if(x==0)return 0;
tot++;c[tot]=c[x];c[tot].v*=tg;c[tot].tg*=tg;
return tot;
}
void Pushdown(int x){
if(c[x].tg!=1){
c[x].l=NewNode(c[x].l,c[x].tg);
c[x].r=NewNode(c[x].r,c[x].tg);
c[x].tg=1;
}
}
int merge(int x,int y){
if(!x||!y)return x+y;
Pushdown(x);Pushdown(y);
if(c[x].v<c[y].v)swap(x,y);
int z=++tot;c[z]=c[x];
c[z].l=merge(c[x].r,y);
c[z].r=c[x].l;c[z].tg=1;
return z;
}
void init(){
int i,j,k;LL pr,prm;
scanf("%lld%d",&N,&K);
for(i=2;i<=128;i++)
if(!vst[i]){
p[++p[0]]=i;
for(j=i+i;j<=128;j+=i)vst[j]=1;
}
f[0][0]=1;tot=1;g[0][0]=1;
c[f[0][0]].v=c[f[0][0]].tg=1;
for(i=1;i<=p[0];i++){
f[i][0]=f[0][0];g[i][0]=1;
for(pr=p[i],j=1;pr>0&&pr<=N;j++,pr=pr*p[i]){
f[i][j]=0;
for(prm=p[i],k=1;k<=j;k++,prm*=p[i])
f[i][j]=merge(f[i][j],NewNode(g[i-1][j-k],prm));
q.push(node(i,j,c[f[i][j]].v));
g[i][j]=merge(g[i-1][j],f[i][j]);
}
}
}
void solve(){
int i,j;
for(i=1;i<=K;i++){
node x=q.top();q.pop();
if(i==K){
printf("%lld\n",x.v);
return;
}
Pushdown(f[x.i][x.k]);
f[x.i][x.k]=merge(c[f[x.i][x.k]].l,c[f[x.i][x.k]].r);
q.push(node(x.i,x.k,c[f[x.i][x.k]].v));
}
}
int main(){
init();
solve();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: