CF1285F Classical?

Link
(A=max(a_i))
先枚举(g),然后计算满足(gcd(a_i,a_j)=g)的答案。
考虑从大到小枚举集合中的数,假如现在枚举到(x),若存在(y>x)满足(gcd(x,y)=g),那么所有((x,y))内的数都不会对答案有贡献了。
因此我们可以弹栈直到栈中没有数与(x)互质,弹栈的时候计算贡献。
随之而来的问题就是如何计算栈中有多少与(x)互质的数,设(cnt_x)表示(x)的出现次数,考虑经典反演:
(sumlimits[gcd(x,y)=1]cnt_y=sumlimits_{d|x}mu(d)sumlimits_{d|y}cnt_y)
那么我们维护(cnt'_x=sumlimits_{x|y}cnt_y)即可。
这样做的时间复杂度为(O(nlog^2n))
那么我们最开始将(a_i)的所有因数都加入集合,然后只需要枚举(gcd(a_i,a_j)=1)跑一遍即可得到答案。
最后记得特判(operatorname{lcm}(a_i,a_i))的情况。
时间复杂度为(O(Alog A))

#include<cctype>
#include<cstdio>
#include<vector>
#include<algorithm>
using i64=long long;
const int N=100007;
int vis[N],cnt[N],mu[N];std::vector<int>fac[N],stk;
int read(){int x=0,c=getchar();while(isspace(c))c=getchar();while(isdigit(c))(x*=10)+=c&15,c=getchar();return x;}
int main()
{
    int n=read(),m=0;i64 ans=0;mu[1]=1;
    for(int i=1,x;i<=n;++i) m=std::max(m,x=read()),vis[x]=1;
    for(int i=1;i<=m;++i) for(int j=i+i;j<=m;j+=i) mu[j]-=mu[i];
    for(int i=1;i<=m;++i) for(int j=i;j<=m;j+=i) if(vis[i]|=vis[j],mu[i]) fac[j].push_back(i);
    for(int i=m;i;--i)
    {
	int num=0;
	if(!vis[i]) continue;
	for(int j:fac[i]) num+=mu[j]*cnt[j];
        for(;num;stk.pop_back())
	{
	    int last=num;
	    for(int j:fac[stk.back()]) if(--cnt[j],!(i%j)) num-=mu[j];
	    if(last^num) ans=std::max(ans,1ll*i*stk.back());
        }
	for(int j:fac[i]) ++cnt[j];
	stk.push_back(i);
    }
    printf("%lld",std::max(ans,1ll*m));
}
原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12918287.html