AtCoder ARC136E Non-coprime DAG

AtCoder 传送门

思路

对于一个奇数 \(x\),能到达它的最大且比它小的数为 \(x - f(x)\),它能到达的最小且比它大的数为 \(x + f(x)\)。因此奇数 \(x\) 对于区间 \([x - f(x) + 1, x + f(x) - 1]\) 都是没有连边的。

考虑两个数 \(x,y\ (x < y)\) 如果 \(x\) 不能到达 \(y\) 需要满足什么条件。

首先 \(x,y\) 一定不能都是偶数。设 \(f(x)\) 表示 \(x\) 的最小质因子,然后分类讨论:

  1. \(2 \mid x\)\(2 \nmid y\),则 \(x \ge y - f(y) + 1\)
  2. \(2 \nmid x\)\(2 \mid y\),则 \(x + f(x) - 1 \ge y\)
  3. \(2 \nmid x\)\(2 \nmid y\),则 \(x + f(x) - 1 \ge y - f(y) + 1\)

\(1\)\(2\) 比较好理解。对于 \(3\),假设此条件不满足,则 \(x\) 到达 \(y\) 可以通过如下的方式:

\[x \to x + f(x) \to y - f(y) \to y \]

第三步是因为 \(x + f(x)\)\(y - f(y)\) 均为偶数。

则我们可以得出,设 \(L_i\) 为最大的且 \([L_i, i]\) 均不能到达 \(i\) 的数,同理 \(R_i\) 为最小的且 \(i\) 不能到达 \([i+1,R_i]\) 的数。对于 \(x\)

  • \(x = 1\),则 \(L_x = 1\)\(R_x = n\),因为 \(1\) 不和任何数连边。
  • \(2 \mid x\),则 \(L_x = x\)\(R_x = x\)
  • \(2 \nmid x\),则 \(L_x = x - f(x) + 1\)\(R_x = x + f(x) - 1\)

因此对于每组 \([L_i, R_i]\) 区间加,最后查询哪个单点的值最大即可。

时间复杂度 \(O(n)\)

代码

code
/*

p_b_p_b txdy
AThousandSuns txdy
Wu_Ren txdy
Appleblue17 txdy

*/

#include <bits/stdc++.h>
#define pb push_back
#define fst first
#define scd second
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 1000100;
const int N = 1000000;

ll n, a[maxn], mpr[maxn], pr[maxn], tot, d[maxn];
bool vis[maxn];

void init() {
	for (int i = 2; i <= N; ++i) {
		if (!vis[i]) {
			pr[++tot] = i;
			mpr[i] = i;
		}
		for (int j = 1; j <= tot && i * pr[j] <= N; ++j) {
			vis[i * pr[j]] = 1;
			mpr[i * pr[j]] = pr[j];
			if (i % pr[j] == 0) {
				break;
			}
		}
	}
}

void solve() {
	scanf("%lld", &n);
	for (int i = 1; i <= n; ++i) {
		scanf("%lld", &a[i]);
	}
	for (int i = 2; i <= n; ++i) {
		if (i & 1) {
			d[i - mpr[i] + 1] += a[i];
			d[i + mpr[i]] -= a[i];
		} else {
			d[i] += a[i];
			d[i + 1] -= a[i];
		}
	}
	ll ans = 0;
	for (int i = 1; i <= n; ++i) {
		d[i] += d[i - 1];
		ans = max(ans, d[i]);
	}
	printf("%lld\n", ans + a[1]);
}

int main() {
	init();
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

posted @ 2022-07-21 16:28  zltzlt  阅读(125)  评论(0)    收藏  举报