ARC136E Non-coprime DAG [关键性质题]
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;
}