CF 1285 F.クラシック?

効果の対象に

所与のアレイ\(A \)二つの数値から選択は、従って最大の最小公倍数は、値の最小公倍数を見つけること。

制限:長さ\(N-(2 \ n型のLeq \のLeq 10 ^ 5)\) \(1 \ルa_iを\ル5 ^ 10 \)。

説明します

一見古典的なタイトルは、いくつかの事前知識が必要です。

事前知識。1 \(O(N \ログ\ N-)\)シーク機能メビウス

ほぼ線形の存在を求める方法が、この方法は非常に短いコードですが。
コードは以下の通りであります:

    mu[1]=1;
    for(int i=1;i<N;i++){
        for(int j=2*i;j<N;j+=i){
            mu[j]-=mu[i];
        }
    }

なぜ、このアプローチは、右ですか?
これは、次の定理によって保証されています。

定理1: \
[\ Sigma_ {D | N} \ MU(D)= \開始{ケース} 0&N \ NEQ 1 \\ 1&N = 1つの\端{ケース} \]

証明:
N-1 =明確。
場合、N> 1、nは一意のk素数で、分解の:
\ [N = \ Piは^ {K} _ {I = 1} {P_I} ^ {M_I} \]
次に、n個のすべての要因を考慮する係数a場合\(M_I \ GEQ 2 \) メビウス関数によって定義され、その値が0である、と考え値\(M_I = 0,1 \)因子。

仮定(M_I \)\番号1である\(U \) 全ての\(\ M_I)と分布\(C_k ^ U \)次に、種。
\ [\ Sigma_ {D | N
} \ MU(D)= \シグマ_ {U = 1} ^ {K}(-1)^ K C_k ^ U \] あっ二項定理:
\ [\シグマ_ {U = 1} ^ {K
}(-1)^ K C_k ^ U = 0 \] したがって:
| \ MU(D)= 0 \] N- \ [\ Sigma_ {D}

2事前知識

定理2列の数を考える\(A \)と数\(X \) 列数\(A \)\(X \)素数の数である:
\ [\ sum_ {D | X} \ MU (D)CNT_D \]
前記\(CNT_D \)の列数を意味\(\)はどのように多くの数であり、(D \)\倍数。

私のレベルに制限され、我々はこの定理を証明することはできません。しかし、私は手段があればということで、おそらくそれを知っている(D = 1 \)\総数であるので、(X \)\ヶ月、と仮定して(X \)\素因数2,3,5,11を持っている、あなたは2,3を失うする必要があります同時に、5と11の倍数の数が、これは、2、3(6)が失わ繰り返されたの数倍の唯一の要因であるので、バック追加するなど係数メビウス関数です。

事前知識3

\(N- \)いくつかの要因があり、\(O(N \ \ログ N)\) レベル。

ステップ1

ための\(LCM(X、Y)= \ FRAC {X-Y} {G} \) \(G \)を表す\(Xを\)\(Y \)は、最大公約数です。次のアプローチは、私たちが列挙グラムにしたいということで、その後、すぐに答えを更新しよう。

列挙\(G \)すべてについて、\(G \)複数\(B \)計算し、\(B / G \)配列内部へ。二つの数字ならば、この配列の内部には、\(U \)\(V \)が互いに素である、あなたが使用することができます\(uvgを\)の答えを更新しました。

これが私たちの現在の考えです。ここで、仮定は即座に(したいことができます(O(C)\)\実現可能な、プライム内部の2つの配列の最大数を見つけるのに時間)?

もちろん。、ので\(a_iを\)の範囲の\(10 ^ 5 \)、\ (G \)最大列挙\(10 ^ 5 \) 回毎の最大数は、それが配列因子で挿入されています数\(D \)このステップので、費やした時間がある(\)O(10 ^ 5 * D)\

ステップ2

素早く2つの素数を見つけるあなたの配列を与えるために、そして彼らの製品が最大である:今すぐサブ質問です。

まず、空のスタックを必要としています。

さて、この配列は、我々は降順ショットを取得します。今すぐ右に大きな左少し。

今、左から右に、このプロセスは、数を取得\(X- \)スタックをスローする準備を。しかし、あなたが最初に見て、スタックを投げると何の数が存在しないの前に事前知識を必要とする、3、2の事前知識を用いて算出され、互いに素xは(O(\ nとログ)\ \) 時間。

スタックがある場合は、\(\シグマ\)番目の素数、そしてポップ\(\シグマ\)番目と(X \)\素数を。
そして遭遇数は可能な限り最大のアップデートへの答えは、聞かせてそうすることを、素数である(\シグマ\)\ - 。

これは、それが今よりも後ろに挿入する番号の、最適解を見逃すことはできません\(X \)まだ小さいですが、ポップアップの数が、ポップアップすることは、最後の数よりも小さくなっています。

コード

https://codeforces.com/contest/1285/submission/69300157

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 1e5+1;

int n,m;
int mu[N];
int S[N],t;
vector<int> d[N];
int exist[N];
vector<int> v[N];   // v[g][i] := g*v[g][i] 的值是存在于a[i]的
int cnt[N];

int main() {
    ios::sync_with_stdio(0);
    cin>>n;
    mu[1]=1;
    for(int i=1;i<N;i++){
        for(int j=i;j<N;j+=i){
            if(i!=j) mu[j]-=mu[i];
            d[j].push_back(i);
        }
    }
    long long ans = 0;
    for(int x,i=1;i<=n;i++) {
        cin>>x;
        exist[x]++;
        ans = max(ans,1ll*x);
    }
    for(int g=1;g<N;g++) {
        for(int j=g;j<N;j+=g) {
            for(int k=0;k<exist[j];k++) v[g].push_back(j/g);
        }
        reverse(v[g].begin(),v[g].end());
        // if(v[g].size()) cout<<g<<" - ";
        for(auto x:v[g]) {
            // if(v[g].size()) cout<<x<<" "<<endl;
            int sigma = 0;
            for(auto u:d[x]) sigma += mu[u] * cnt[u];
            // cout<<sigma<<endl;
            while(sigma>0 && t) {
                int u = S[--t];
                if(__gcd(u,x)==1) {
                    ans = max(ans,1ll * g * u * x);
                    sigma--;
                }
                for(auto w:d[u]) {
                    cnt[w]--;   
                }
            }
            S[t++] = x;
            for(auto u:d[x]) cnt[u]++;
        }
        // if(v[g].size()) cout<<endl;
        while(t) {
            int u = S[--t];
            for(auto w:d[u]) {
                cnt[w]--;
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}

おすすめ

転載: www.cnblogs.com/scnucjh/p/12232545.html