【XSY2815】净空(贪心,线段树)
题目要求我们分解为 \(x=\prod_{i=1}^m(c_i!)^{t_i}\cdot p\),那么显然 \(c_i\) 不可能大于等于 \(10^5+3\)(为质数),否则 \(c_i!\) 就会包括这个质数,而 \(x\) 不可能包含这个质因子。
那么肯定是枚举 \(N\) 从 \(10^5+2\) 到 \(2\),过程中不断贪心地试除 \(N!\)。
先对 \(x=\prod_{i=1}^n a_i!\) 分解质因数,得到 \(x=\prod_{i}p_i^{b_i}\)。
假设当前 \(N=\prod_ip_i^{d_i}\),那么能除掉 \(N!\) 的次数为 \(t=\min\limits_i\left(\lfloor\frac{b_i}{d_i}\rfloor\right)\),然后需要将全体的 \(b_i\) 减去 \(t\cdot d_i\)。
从 \(N\) 变到 \(N-1\) 时,发现只有 \(\omega(N)\) 个 \(d_i\) 有变化,而 \(\sum \omega(i)=n\log \log n\)。
于是可以考虑用线段树维护 \(\min\limits_i\left(\lfloor\frac{b_i}{d_i}\rfloor\right)\),对于全局减 \(t\cdot d_i\) 也可以用懒标记维护。
每次对于 \(d_i\) 有变化的位置单点重构 \(d_i\) 即可。
时间复杂度 \(O(n\log n\log \log n)\)。
#include<bits/stdc++.h>
#define N 100010
#define fi first
#define se second
#define mk(a,b) make_pair(a,b)
#define ll long long
#define LNF 0x7fffffffffffffff
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^'0');
ch=getchar();
}
return x*f;
}
const int maxn=100002;
int n;
int cnt,prime[N],minp[N],minq[N],minpq[N];
bool notprime[N];
ll buc[N],b[N],d[N];
ll minQ[N<<2],lazy[N<<2];
ll R[N];
void init()
{
for(int i=2;i<=maxn;i++)
{
if(!notprime[i])
{
prime[++cnt]=i;
minp[i]=cnt,minq[i]=1,minpq[i]=i;
}
for(int j=1,v;j<=cnt&&(v=i*prime[j])<=maxn;j++)
{
notprime[v]=1;
minp[v]=j;
if(!(i%prime[j]))
{
minq[v]=minq[i]+1;
minpq[v]=minpq[i]*prime[minp[i]];
break;
}
minq[v]=1,minpq[v]=prime[j];
}
}
}
void calc(ll *b)
{
for(int i=maxn;i>=2;i--)
{
b[minp[i]]+=buc[i]*minq[i];
buc[i/minpq[i]]+=buc[i];
}
}
void up(int k)
{
minQ[k]=min(minQ[k<<1],minQ[k<<1|1]);
}
void build(int k,int l,int r)
{
if(l==r)
{
minQ[k]=b[l]/d[l];
R[l]=b[l]%d[l];
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
up(k);
}
void downn(int k,ll v)
{
minQ[k]-=v,lazy[k]+=v;
}
void down(int k)
{
if(lazy[k])
{
downn(k<<1,lazy[k]);
downn(k<<1|1,lazy[k]);
lazy[k]=0;
}
}
void update(int k,int l,int r,int x,int y)
{
if(l==r)
{
ll nb=minQ[k]*d[l]+R[l];
d[l]-=y;
if(d[l])
{
minQ[k]=nb/d[l];
R[l]=nb%d[l];
}
else
{
minQ[k]=LNF;
R[l]=nb;
}
return;
}
down(k);
int mid=(l+r)>>1;
if(x<=mid) update(k<<1,l,mid,x,y);
else update(k<<1|1,mid+1,r,x,y);
up(k);
}
int main()
{
n=read();
for(int i=1;i<=n;i++) buc[read()]++;
for(int i=maxn;i>=2;i--) buc[i]+=buc[i+1];
init();
calc(b);
memset(buc,0,sizeof(buc));
for(int i=1;i<=maxn;i++) buc[i]=1;
calc(d);
vector<pair<int,ll> >vec;
build(1,1,cnt);
for(int i=maxn;i>=2;i--)
{
ll t=minQ[1];
if(t)
{
vec.push_back(mk(i,t));
downn(1,t);
}
int x=i;
while(x>1)
{
update(1,1,cnt,minp[x],minq[x]);
x/=minpq[x];
}
}
printf("%d\n",(int)vec.size());
for(auto now:vec)
printf("%d %lld\n",now.fi,now.se);
return 0;
}
/*
3
7 9 13
*/