ARC136E Non-coprime DAG [關鍵性質題]

chenwenmo發表於2024-10-10

Description

構造一個有向圖,\(i\to j\) 的邊存在,當且僅當 \(i<j\)\(\text{gcd}(i,j)>1\),求一個反鏈 \(S\),使得 \(\sum\limits_{i\in S}A_i\) 最大。
反鏈指的是一個點集,任意兩點都不能到達。

Solution

考慮 \(i\) 可以到達 \(j\) 需要滿足什麼條件,下面我們欽定 \(i<j\),設 \(f(i)\) 表示 \(i\) 的最小質因子,

  • \(1\) 不能到達任何點,也不能被任何點到達。
  • \(i\)\(j\) 都是偶數時,顯然存在 \(i\to j\)
  • \(i\) 是奇數,\(j\) 是偶數時,\(i\to j\) 存在當且僅當 \(i+f(i)\le j\)
  • \(i\) 是偶數,\(j\) 是奇數時,\(i\to j\) 存在當且僅當 \(i\le j-f(j)\)
  • \(i\)\(j\) 都是奇數時,\(i\to j\) 存在當且僅當 \(i+f(i)\le j-f(j)\)

如何理解以上式子呢,
可以將 \(i+f(i)\) 看作 \(i\) 能到達的 編號最小的點,將 \(j-f(j)\) 看作 能到達 \(j\) 編號最大的點,
\(i\)\(j\) 都是奇數,那加上或減去 \(f\) 就應當是偶數,我們知道偶數是可以到達的,但僅限於小的編號到大的編號,所以 \(i\to j\) 存在當且僅當 \(i+f(i)\le j-f(j)\)

於是我們可以把 \(i\) 的影響範圍看作一個區間 \([i-f(i)+1,f+f(i)-1]\),這個區間內所有點都是和 \(i\) 沒邊的,偶數 \(i\) 的影響區間是 \([i,i]\)
那麼我們對於每個點,將它的影響區間都加上它的權值 \(a_i\)。我們知道反鏈之間是沒邊的,所以反鏈中所有點的影響區間都會有交集,因此累加權值的時候就剛好計算了答案,取最大的一個即可。
對於區間加,可以用差分維護,\(dif[i-f(i)+1]+a[i]\to dif[i-f(i)+1]\)\(dif[i+f(i)]-a[i]\to dif[i+f(i)]\)

Code

const int N = 1e6 + 5;

int n;
ll a[N], dif[N];
int f[N], prime[N], cnt;

void Solve(){
    cin >> n;
    for(int i = 1; i <= n; i++){
        cin >> a[i];
    }

    for(int i = 2; i <= n; i++){
        if(!f[i]) f[i] = prime[++cnt] = i;
        for(int j = 1; j <= cnt && prime[j] <= n / i; j++){
            f[prime[j] * i] = prime[j];
            if(i % prime[j] == 0) break;
        }
    }

    for(int i = 2; i <= n; i++){
        if(i & 1) dif[i - f[i] + 1] += a[i], dif[i + f[i]] -= a[i];
        else dif[i] += a[i], dif[i + 1] -= a[i];
    }
    dif[1] += a[1], dif[n + 1] -= a[1];

    ll ans = 0;
    for(int i = 1; i <= n; i++){
        dif[i] += dif[i - 1];
        ans = max(ans, dif[i]);
    }
    cout << ans << endl;
}

相關文章