题解 CF1285F【Classical?】

· · 题解

CF1285F Classical?解题报告:

更好的阅读体验

题意

给定 n 个数,a_{1\cdots n},求 \max\{\text{lcm}(a_i,a_j)\mid1\leqslant i,j\leqslant n\}。(1\leqslant n,a_i\leqslant 10^5

分析

我们发现取出所有数的复杂度是 $O(\sum\lfloor\frac{n}{i}\rfloor)=O(n\log n)$ 时间的,所以我们可以直接取出所有数来判断。 我们将取出来的所有数除以 $g$,那么数对的 $\gcd$ 为 $1$,从大到小扫,设扫到了 $x$,如果之前有与它互素的数,那么仅有最大的那个数有用,且与它互素的数在后面一定没有用了。 这是一个很好的性质,考虑扫的时候怎么快速判断是否存在与它互素的数: 与它互素的数实在太多了,无法逐一枚举,但是所有数的因子总数却只有 $O(n\log n)$ 级别,于是我们考虑每次只枚举每个数的因子。 具体地,我们发现可以容斥计算与 $x$ 互素的数个数:(设 $tot_i$ 表示 $i$ 的倍数出现次数) $$\sum_{d\mid x} \mu_dcnt_d$$ 加入一个数和删除一个数暴力算贡献,判断的时候就直接查,然后弹栈,这样的复杂度为 $O(n\log^2 n)$。 能不能再给力一点呢? 我们发现刚刚的方法只能处理 $\gcd=1$ 的情况,那么我们可以取出所有数的因子加入序列中,对于 $\text{lcm}$ 最大的数对 $(x,y)$,它们的两个因子 $x'=\frac{x}{\gcd(x,y)},y'=y$,满足 $\text{lcm}(x,y)=\text{lcm}(x',y')$,于是一定存在两个互素的数 $\text{lcm}$ 仍为最大值。 时间复杂度:$O(n\log n)$。(默认 $n$ 与值域同阶) ## 代码 ``` #include<stdio.h> #include<vector> using namespace std; const int maxn=100005; int n,maxx,top; int a[maxn],ok[maxn],cnt[maxn],miu[maxn],stk[maxn]; long long ans; vector<int>d[maxn]; int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]),ok[a[i]]=1,maxx=max(maxx,a[i]); ans=maxx,miu[1]=1; for(int i=1;i<=maxx;i++){ for(int j=2*i;j<=maxx;j+=i){ miu[j]-=miu[i],d[j].push_back(i); if(ok[j]) ok[i]=1; } d[i].push_back(i); } for(int i=maxx;i>=1;i--){ if(ok[i]==0) continue; int sum=0; for(int j=0;j<d[i].size();j++) sum+=miu[d[i][j]]*cnt[d[i][j]]; while(sum>0){ int dec=0; for(int j=0;j<d[stk[top]].size();j++){ cnt[d[stk[top]][j]]--; if(i%d[stk[top]][j]==0) dec+=miu[d[stk[top]][j]]; } if(dec) sum-=dec,ans=max(ans,1ll*i*stk[top]); top--; } for(int j=0;j<d[i].size();j++) cnt[d[i][j]]++; stk[++top]=i; } printf("%lld\n",ans); return 0; } ```