CF1285F Classical?
太神仙了。Orz \(\color{black}{\texttt{c}}\color{black}{\texttt{yn2006}}\)
这个值域 \(10^5\) 使我们想到枚举 \(\gcd\) 。
假设我们枚举 \(\gcd=t\) ,那么我们扫描所有 \(t\) 的倍数 \(x\),把 \(\dfrac{x}{t}\) 都丢进一个数组,并且从大到小排序。
嗯,直觉是数越大 \(\operatorname{lcm}\) 也就可能越大。只不过有可能会有不互质的情况导致又被约掉一些因子。
又发现我们只需要在数组里的数互质的情况统计贡献即可,不互质的话说明 \(\gcd>t\) ,会在别的地方被统计到。
那么我们只需要找到最大的与它互质的数即可!于是从大到小排序就没错了。
考虑按顺序把这个数组里的东西丢进栈。
我们发现只需要保留一个与这个数互质的数,其余全都可以弹掉。后面的数找不到互质的数也没关系,因为它们只有与更大的数配对才有可能更新答案。
而找到最大的与它互质的数可以通过找到栈中有几个与它互质的数然后不断弹栈即可。
至于找到一个集合内有几个与它互质的数,这是个人口普查形式的莫反。但是我居然推了10来分钟,还是写一写吧(一个月没搞莫反就忘了)
令 \(m=\max\{a_i \}\) ,\(c_i\) 表示 \(i\) 在集合中的出现次数。
考虑对于每一个 \(d\) 维护 \(f_d=\sum_{i=1}^{\frac{m}{d}}c_{id}\),每次加入或删除一个数 \(x\) 只会影响到 \(d|x\) 的 \(f_d\) ,而 \(id=x\) ,直接修改就行。
复杂度是 \(O(\sum \sigma(i)^2)\) ,\(\sigma(i)\) 表示 \(i\) 的因数个数。实测 \(1e5\) 大概 \(9e7\) ,CF随便跑。
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define mkp(x,y) make_pair(x,y)
#define pb(x) push_back(x)
#define sz(v) (int)v.size()
typedef long long LL;
typedef double db;
template<class T>bool ckmax(T&x,T y){return x<y?x=y,1:0;}
template<class T>bool ckmin(T&x,T y){return x>y?x=y,1:0;}
#define rep(i,x,y) for(int i=x,i##end=y;i<=i##end;++i)
#define per(i,y,x) for(int i=y,i##end=x;i>=i##end;--i)
inline int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=0;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f?x:-x;
}
#define N 100005
int n,m,a[N],stk[N],top,mu[N],pri[N/10],pct,b[N],c[N],cnt[N];
LL ans;
bool vis[N];
vector<int>d[N];
void init(){
mu[1]=1;
rep(i,2,m){
if(!vis[i])pri[++pct]=i,mu[i]=-1;
for(int j=1;j<=pct&&i*pri[j]<N;++j){
vis[i*pri[j]]=1;
if(i%pri[j]==0){mu[i*pri[j]]=0;break;}
mu[i*pri[j]]=-mu[i];
}
}
for(int i=1;i<=m;++i)
for(int j=1;i*j<=m;++j)
d[i*j].pb(i);
}
void upd(int x){
rep(i,0,sz(d[x])-1)++c[d[x][i]];
}
void del(int x){
rep(i,0,sz(d[x])-1)--c[d[x][i]];
}
int calc(int x){
int res=0;
rep(i,0,sz(d[x])-1)
res+=mu[d[x][i]]*c[d[x][i]];
return res;
}
signed main(){
n=read();
rep(i,1,n)a[i]=read(),ckmax(m,a[i]),++cnt[a[i]];
sort(a+1,a+n+1,greater<int>());
init();
rep(t,1,m){
b[0]=0;
for(int i=1;i*t<=m;++i)
rep(j,1,cnt[i*t])b[++b[0]]=i;
reverse(b+1,b+b[0]+1);
rep(i,1,b[0]){
int now=calc(b[i]);
while(now>=1){
if(__gcd(stk[top],b[i])==1){
if(now==1)break;
else --now;
}
del(stk[top]),--top;
}
if(now==1)ckmax(ans,1ll*b[i]*stk[top]*t);
stk[++top]=b[i],upd(b[i]);
}
while(top)del(stk[top--]);
}
printf("%lld\n",ans);
}