4524: [Cqoi2016]伪光滑数
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 280 Solved: 133
[ Submit][ Status][ Discuss]
Description
若一个大于R的整数J的质因数分解有F项,其最大的质因子为ak,并且满足ak^k≤N,
ak<128,我们就称整数J为N-伪光滑数。
现在给出L,求所有整数中,第E大的N-伪光滑数。
Input
只有一行,为用空格隔开的整数L和E。
2 ≤ N ≤ 10^18, 1 ≤ K ≤ 800000,保证至少有 E 个满足要求的数
Output
只有一行,为一个整数,表示答案。
Sample Input
12345 20
Sample Output
9167
HINT
Source
正解是可持久化可并堆 + dp,,看了题解才会= =
先筛出2~128内所有质数,分别给它们一个编号
定义f[i][j]:质因数最大为pri[i],由j个质因数组成的数的集合
定义g[i][j]:质因数最大为pri[1] ~ pri[i],由j个质数组成的数的集合
定义U*g为集合U中所有数字乘以g,定义A + B为集合A,B取并集
那么很好写出f,g的方程,f[i][j] = ∑g[i-1][k]*pri[i]^(j-k),g[i][j] = g[i-1][j] + f[i][j]
询问的话先把所有f[i][j]中最大的数都扔进堆里,每次取出最大的数字,把它所在集合的次大数扔进堆
不断重复K次就是答案了
f,g的集合可以用可持久化可并堆 + 懒惰标记解决
这样就能保证存数集最大数的那个堆里的元素大小线性,因为每次取出一个数新放两个数
#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<bitset>
using namespace std;
typedef long long LL;
typedef double DB;
const int maxn = 8E5 + 80;
const int T = 15;
struct Heap{
int L,ch[2]; LL val,Mark;
}h[maxn*T];
struct Node{
LL val; int num; Node(){}
Node(int num,LL val): num(num),val(val){}
bool operator < (const Node &B) const {return val < B.val;}
};
LL N,mi[100][100],pri[100];
int K,tot,cnt,f[100][100],g[100][100];
bool not_pri[200];
priority_queue <Node,vector<Node>,less<Node> > Q;
void Pre_Work()
{
for (int i = 2; i < 128; i++)
{
if (!not_pri[i]) pri[++tot] = i;
for (int j = 1; j <= tot; j++)
{
int Nex = i*pri[j];
if (Nex >= 128) break;
not_pri[Nex] = 1;
if (i % pri[j] == 0) break;
}
}
for (int i = 1; i <= tot; i++)
{
mi[i][0] = 1;
for (int j = 1; j <= 64; j++)
{
if ((DB)(pri[i]) > (DB)(N) / (DB)(mi[i][j-1])) break;
mi[i][j] = mi[i][j-1]*pri[i];
}
}
}
void pushdown(int x)
{
if (h[x].Mark == 1) return;
h[x].val *= h[x].Mark;
for (int i = 0; i < 2; i++)
if (h[x].ch[i])
{
h[++cnt] = h[h[x].ch[i]];
h[cnt].Mark *= h[x].Mark; h[x].ch[i] = cnt;
}
h[x].Mark = 1;
}
int Merge(int x,int y)
{
if (!x) return y; if (!y) return x;
pushdown(x); pushdown(y);
if (h[x].val < h[y].val) swap(x,y);
int ret = ++cnt; h[ret] = h[x];
h[ret].ch[1] = Merge(h[ret].ch[1],y);
if (h[h[ret].ch[1]].L > h[h[ret].ch[0]].L)
swap(h[ret].ch[0],h[ret].ch[1]);
h[ret].L = h[h[ret].ch[1]].L + 1; return ret;
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
cin >> N >> K; Pre_Work();
f[0][0] = g[0][0] = ++cnt; h[cnt].Mark = h[cnt].val = 1;
for (int i = 1; i <= tot; i++)
for (int j = 0; j <= 64; j++)
{
if (!mi[i][j]) {g[i][j] = g[i-1][j]; continue;}
for (int k = 0; k < j; k++) if (g[i-1][k])
{
LL now = h[g[i-1][k]].val*h[g[i-1][k]].Mark;
h[++cnt] = h[g[i-1][k]]; h[cnt].Mark *= mi[i][j-k];
f[i][j] = Merge(f[i][j],cnt);
}
g[i][j] = Merge(g[i-1][j],f[i][j]);
if (!f[i][j]) continue;
pushdown(f[i][j]); Q.push(Node(f[i][j],h[f[i][j]].val));
}
for (int I = 1; ; I++)
{
Node k = Q.top(); Q.pop(); int now = k.num;
if (I == K) {cout << k.val; break;}
for (int i = 0; i < 2; i++)
if (h[now].ch[i])
{
int Nex = h[now].ch[i]; pushdown(Nex);
Q.push(Node(Nex,h[Nex].val));
}
}
return 0;
}