CF1285F Classical?
Description
给定 \(\{a_n\}\),求 \(\max\{lcm(a_i,a_j)\}\)
Solution
一个显然的想法是枚举 gcd,然后求去掉 gcd 后互质的两个数的乘积最大值。一个显然的性质是如果 \(x\) 和 \(y\) 互质,那么对任意 \(y'\leq y\) 都不会和 \(x'\leq x\) 来更新答案。维护一个栈,从大到小枚举 \(x\),找到最大的与 \(x\) 互质的 \(y\),然后把栈里面所有 \(y'\leq y\) 都弹掉。
如何找到最大的与 \(x\) 互质的数?实际上我们只需要知道栈里面存不存在与 \(x\) 互质的数。如果存在,那么就一直弹栈,因为迟早都要删掉。直到没有互质的了,最后一个被弹掉的就是要找的数。与 \(x\) 互质的数的个数为(其中 \(c_i\) 表示 \(i\) 的个数)
\[\sum c_i [gcd(i,x)=1]=\sum c_i\sum_{d|i,d|x} \mu(d)=\sum_{d|x} \mu(d)\sum_{d|i}c_i
\]
所以只需要时刻维护 \(w_d\) 表示 \(d\) 的倍数的个数。具体而言,预处理出每个数的约数,和 \(\mu\),弹栈和入栈的时候更新就可以了。
复杂度 \(O(\sum_{d=1}^{|V|} \frac{|V|}{d}|V|^{\frac{1}{3}})=O(|V|^{\frac{4}{3}}\log |V|)\)
#include<stdio.h>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
inline int read(){
int x=0,flag=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-') flag=0;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
return flag? x:-x;
}
const int N=1e5+7;
bool mk[N];
int n,a[N],cnt=0,p[N],w[N],sta[N],top=0,c[N],mu[N];
vector<int> D[N];
int gcd(int x,int y){
return y? gcd(y,x%y):x;
}
int main(){
n=read(); int rg=0;
for(int i=1,x;i<=n;i++)
rg=max(rg,x=read()),c[x]++;
ll ans=0; mu[1]=1;
for(int i=2;i<=rg;i++){
if(!mk[i]){p[++cnt]=i,mu[i]=-1;}
for(int j=1;j<=cnt&&p[j]*i<=rg;j++){
mk[p[j]*i]=1;
if(i%p[j]==0) break;
mu[i*p[j]]=-mu[i];
}
}
for(int i=1;i<=rg;i++)
for(int j=i;j<=rg;j+=i)
D[j].push_back(i);
for(int d=1;d<=rg;d++){
n=0;
for(int i=d;i<=rg;i+=d)
for(int j=1;j<=c[i];j++) a[++n]=i/d;
for(int i=n;i;i--){
int y=0,s=0;
for(int j=0;j<D[a[i]].size();j++){
int x=D[a[i]][j];
s+=w[x]*mu[x];
}
while(s){
y=sta[top--];
if(gcd(y,a[i])==1) s--;
for(int j=0;j<D[y].size();j++)
w[D[y][j]]--;
}
if(y) ans=max(ans,1ll*y*a[i]*d);
sta[++top]=a[i];
for(int j=0;j<D[a[i]].size();j++)
w[D[a[i]][j]]++;
}
while(top){
int y=sta[top--];
for(int j=0;j<D[y].size();j++)
w[D[y][j]]--;
}
}
printf("%lld",ans);
}