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_isum_{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);
}
原文地址:https://www.cnblogs.com/wwlwQWQ/p/15171848.html