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);
}
posted @ 2021-08-22 11:57  Kreap  阅读(24)  评论(0编辑  收藏  举报