Codeforces Global Round 26 (A - E)

Codeforces Global Round 26

A

如果 \(a_1 = a_n\),无解。

如果 \(a_2 = a_n\)\(a_1, a_2\) 涂成红色,否则只把 \(a_1\) 涂成红色。

void solve() {
	cin >> n;
	for(int i = 1; i <= n; ++ i) cin >> a[i];
	if(a[1] == a[n]) {
		cout << "NO\n";
		return;
	}
	cout << "YES\n";
	if(a[2] != a[n]) {
		cout << "R";
		for(int i = 2; i <= n; ++ i) {
			cout << "B";
		}
		cout << '\n';
		return;
	}
	cout << "RR";
	for(int i = 3; i <= n; ++ i) {
		cout << "B";
	}
	cout << '\n';
}

B

如果首位不等于 \(1\),无解。

否则可以推出两个数 \(a + b = x\) 每一位的和,且这个和一定属于 \([10, 18]\),否则无解。

例如:\(1393938\)

  • \(a_0 + b_0 = 18\)
  • \(a_1 + b_1 = 13 - 1\)(一定有进位)。
  • \(a_2 + b_2 = 19 - 1\)

以此类推。

void solve() {
	ll x; cin >> x;
	auto s = to_string(x);
	int n = s.length();
	if(s[0] != '1') {
		cout << "NO\n";
		return;
	}
	for(int i = 0; i <= n - 2; ++ i) {
		int x = 10 + s[i + 1] - '0';
		if(i != n - 2) -- x;
		if(x < 10 || x > 18) {
			cout << "NO\n";
			return;
		}
	}
	cout << "YES\n";
}

C1

最多只会用一次操作二。

反证法,考虑最后两次操作二分别对应 \(c + a_i\)\(c + a_j\)。显然 \(c + a < 0\) ,否则没必要用操作二。如果 \(i\) 处用了操作 \(1\)\(c + a_j\) 将变得更小,从而使答案增大。

维护最小前缀和 \(x = \min(s_i, 0)\),则最终的 \(c = s_n - 2x\)

void solve() {
	ll n, mi = 0, s = 0;
	cin >> n;
	for(int i = 1; i <= n; ++ i) {
		int x; cin >> x;
		mi = min(mi, s += x);
	}
	cout << s - mi * 2 << '\n';
}

C2

延续 C1 的思考方向。

如果 \(x = 0\),操作中不出现负数。因此操作一操作二是等效的,方案数为 \(2^n\)

如果 \(s_i = x\),说明可以在这一步进行操作二达到最终的 \(c\)

\(k = \sum\limits_{j <i}[s_j\ge0]\),表示在 \(i\) 之前有 \(k\) 步可以用两种操作。因为 \(c \ge 0\),所以在 \(i\) 之后的所有的操作都是非负的,贡献为 \(2^k \times 2^{n - i}\)

void solve() {
	cin >> n;
	mi = 0;
	for(int i = 1; i <= n; ++ i) {
		cin >> s[i];
		mi = min(mi, s[i] += s[i - 1]);
	}
	if(mi == 0) {
		cout << p[n] << '\n';
		return;
	}
	ll ans = 0;
	for(int i = 1, k = 0; i <= n; ++ i) {
		if(s[i] >= 0) ++ k;
		if(s[i] == mi) {
			ans = (ans + p[k] * p[n - i]) % P;
		}
	}
	cout << ans << '\n';
}

D

\(s\) 长度为 \(n\)。特判全为 a 的情况,共 \(n - 1\) 种方案。

\(s\) 中非 a 字符的数量为 \(m\)

如果 \(t\) 中有 \(k\) 个非 a 字符,把 \(t\) 掐头去尾忽略前后的 a 后,原串里一定恰好存在 \(\dfrac{m}{k}\)\(t'\),且 \(k\mid m\)

枚举 \(k\)。记录第 \(i\) 个非 a 字符的位置为 \(p_i\)(从 \(0\) 开始),如果 \(s_{p_i} \ne s_{p_i - k}\) 或不在分割处的 \(p_i - p_{i - 1}\ne p_{i - k} - p_{i - k - 1}\)\(t'\) 不合法。

\(t'\) 还原为 \(t\),枚举左边有的 a 个数 \(l \in [0, p_0]\)

\(x\) 为分割处的最小间隔 \(\min(p_i - p_{i - 1}),\ k \mid i\),则右边的 a 个数 \(r \in [0, \min(x - l, n - p_{m - 1} - 1)]\)

void solve() {
	string s;
	cin >> s;
	int n = s.length();
	if(count(s.begin(), s.end(), 'a') == n) {
		cout << n - 1 << '\n';
		return;
	}	
	vector<int> a;
	for(int i = 0; i < n; ++ i) {
		if(s[i] != 'a') {
			a.eb(i);
		}
	}
	int m = a.size();
	ll ans = 0;
	for(int i = 1; i <= m; ++ i) {
		if(m % i) {
			continue;
		}
		int ok = 1;
		for(int j = i; j < m; ++ j) {
			int o = j % i;
			if(s[a[j]] != s[a[o]] || (o && a[o] - a[o - 1] != a[j] - a[j - 1])) {
				ok = 0;
				break;
			}
		}
		if(ok) {
			int mi = n;
			for(int j = i; j < m; j += i) {
				mi = min(mi, a[j] - a[j - 1] - 1);
			}
			int r = n - a.back() - 1;
			for(int l = 0; l <= a[0]; ++ l) {
				ans += max(0, min(r + 1, mi - l + 1));
			}
		}
	}
	cout << ans << '\n';
}

E

把一个点的父亲儿子都加到 \(T_2\) 后,这个点就是叶子,且与之直接相连的点都不是叶子。(所有相邻点都是这个点的祖先)。

所有的叶子构成一个独立集,我们找去除根后最大的,类似 上司的舞会

枚举每个节点作为初始的根,换根 dp。如果根本身就是叶子还要在加一。

具体来说,第一次扫描以 \(1\) 为根求出 \(f_{x, 1/0}\) 表示以 \(x\) 为根的子树中 \(x\) 选/不选的最大独立集:\(\begin{cases}f_{x, 0} = \sum_{y \in g_x} \max(f_{y, 0}, f_{y, 1}) \\ f_{x, 1} = \sum_{y \in g_x} f_{y, 0}\end{cases}\)

第二次扫描求出 \(h_{x, 1/0}\) 表示选/不选 \(x\) 的最大独立集,\(h_{1, 0/1} = f_{1, 0/1},\ \begin{cases}h_{x, 0} = \max(h_{fa, 1},\ f_{x, 0} + (h_{fa, 0} - \max(f_{x, 1}, f_{x, 0})))\\h_{x, 1} = f_{x, 1} + (h_{fa, 0} - \max(f_{x, 1}, f_{x, 0})) \end{cases}\)

\(h_{x, 0} + [x \texttt{ is leaf}]\) 更新答案。

void solve() {
	int n;
	cin >> n;
	vector<vector<int>> g(n + 1);
	for(int i = 1; i < n; ++ i) {
		int x, y;
		cin >> x >> y;
		g[x].eb(y);
		g[y].eb(x);
	}
	vector<array<int, 2>> f(n + 1, {0, 0});
	auto dfs = [&](auto &&dfs, int x, int fa) -> void {
		f[x][0] = 0;
		f[x][1] = 1;
		for(int y : g[x]) {
			if(y != fa) {
				dfs(dfs, y, x);
				f[x][0] += max(f[y][0], f[y][1]);
				f[x][1] += f[y][0];
			}
		}
	};
	dfs(dfs, 1, 0);
	vector<array<int, 2>> h(n + 1);
	
	h[1][0] = f[1][0];
	h[1][1] = f[1][1];
	int ans = h[1][0] + (g[1].size() == 1);
	
	auto dfs2 = [&](auto &&dfs2, int x, int fa) -> void {
		int tmp = h[fa][0] - max(f[x][0], f[x][1]);
		h[x][1] = f[x][1] + tmp; 
		h[x][0] = max(h[fa][1], f[x][0] + tmp);
		tmp = h[x][0] + (g[x].size() == 1);
		ans = max(ans, tmp);
		for(int y : g[x]) {
			if(y != fa) {
				dfs2(dfs2, y, x);
			}
		}
	};
	for(int y : g[1]) {
		dfs2(dfs2, y, 1);
	}
	cout << ans << '\n';
}
posted @ 2024-06-10 10:20  Lu_xZ  阅读(281)  评论(0编辑  收藏  举报