题目要求我们分解为 x = ∏ i = 1 m ( c i ! ) t i ⋅ p x=\prod_{i=1}^m(c_i!)^{t_i}\cdot p x=∏i=1m(ci!)ti⋅p,那么显然 c i c_i ci 不可能大于等于 1 0 5 + 3 10^5+3 105+3(为质数),否则 c i ! c_i! ci! 就会包括这个质数,而 x x x 不可能包含这个质因子。
那么肯定是枚举 N N N 从 1 0 5 + 2 10^5+2 105+2 到 2 2 2,过程中不断贪心地试除 N ! N! N!。
先对 x = ∏ i = 1 n a i ! x=\prod_{i=1}^n a_i! x=∏i=1nai! 分解质因数,得到 x = ∏ i p i b i x=\prod_{i}p_i^{b_i} x=∏ipibi。
假设当前 N = ∏ i p i d i N=\prod_ip_i^{d_i} N=∏ipidi,那么能除掉 N ! N! N! 的次数为 t = min i ( ⌊ b i d i ⌋ ) t=\min\limits_i\left(\lfloor\frac{b_i}{d_i}\rfloor\right) t=imin(⌊dibi⌋),然后需要将全体的 b i b_i bi 减去 t ⋅ d i t\cdot d_i t⋅di。
从 N N N 变到 N − 1 N-1 N−1 时,发现只有 ω ( N ) \omega(N) ω(N) 个 d i d_i di 有变化,而 ∑ ω ( i ) = n log log n \sum \omega(i)=n\log \log n ∑ω(i)=nloglogn。
于是可以考虑用线段树维护 min i ( ⌊ b i d i ⌋ ) \min\limits_i\left(\lfloor\frac{b_i}{d_i}\rfloor\right) imin(⌊dibi⌋),对于全局减 t ⋅ d i t\cdot d_i t⋅di 也可以用懒标记维护。
每次对于 d i d_i di 有变化的位置单点重构 d i d_i di 即可。
时间复杂度 O ( n log n log log n ) O(n\log n\log \log n) O(nlognloglogn)。
#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
*/