比赛链接:

https://vjudge.net/contest/511178

C - Wavy Tree

题意:

长为 \(n\) 的序列,每一步操作可以让 \(a_i\) 变成 \(a_j\),花费为 \(\lvert a_i - a_j \rvert\)
现在要使 \(a_i(1 < i < n)\) 满足 \(a_{i - 1} < a_i > a_{i + 1}\) 或者 \(a_{i - 1} > a_i < a_{i + 1}\),问最少花费多少。

思路:

先确定奇数位是大于两边还是偶数位是大于两边,然后根据贪心的策略,如果 \(a_{i - 1}\)\(a_i\) 不满足条件,修改 \(a_i\) 即可,两种情况的最小值就是答案。

代码:

#include <bits/stdc++.h>
using namespace std;
#define LL long long
void solve(){
	LL n;
	cin >> n;
	vector <LL> a(n), b(n);
	for (int i = 0; i < n; i ++ ){
		cin >> a[i];
		b[i] = a[i];
	}
	LL ans1 = 0;
	for (int i = 1; i < n; i ++ ){
		if ( (i & 1) && a[i - 1] >= a[i]){
			ans1 += a[i - 1] + 1 - a[i];
			a[i] = a[i - 1] + 1;
		}
		else if ( (i % 2 == 0) && a[i - 1] <= a[i]){
			ans1 += a[i] - (a[i - 1] - 1);
			a[i] = a[i - 1] - 1;
		}
	}
	LL ans2 = 0;
	for (int i = 1; i < n; i ++ ){
		if ( (i & 1) && b[i - 1] <= b[i]){
			ans2 += b[i] - (b[i - 1] - 1);
			b[i] = b[i - 1] - 1;
		}
		else if ( (i % 2 == 0) && b[i - 1] >= b[i]){
			ans2 += b[i - 1] + 1 - b[i];
			b[i] = b[i - 1] + 1;
		}
	}
	cout << min(ans1, ans2) << "\n";
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	LL T = 1;
	cin >> T;
	while(T -- ){
		solve();
	}
	return 0;
}

D - Average Replacement

题意:

\(n\) 个人,每个人帽子上有一个数字,\(m\) 条关系,\(u\)\(v\) 是好朋友,好朋友之间会玩游戏,朋友间帽子上的会变成所有人总合的平均值。问经过无数次游戏之后,每个人帽子上的数字是多少。

思路:

每个人对自己和自己的朋友的总贡献是自己帽子上的数 * 度的数量。

代码:

#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 1e5 + 10;
LL n, m, p[N], a[N], deg[N], ans[N], sum[N];
LL get(LL x){
	return (x == p[x] ? x : (p[x] = get(p[x])));
}
void unite(LL x, LL y){
	x = get(x);
	y = get(y);
	if (x != y){
		p[x] = y;
	}
}
void solve(){
	cin >> n >> m;
	for (int i = 1; i <= n; i ++ ){
		scanf("%lld", &a[i]);
		p[i] = i;
		deg[i] = ans[i] = sum[i] = 0;
	}
	for (int i = 0; i < m; i ++ ){
		LL u, v;
		scanf("%lld %lld", &u, &v);
		unite(u, v);
		deg[u] ++ ;
		deg[v] ++ ;
	}
	for (int i = 1; i <= n; i ++ ){
		ans[get(i)] += (deg[i] + 1) * a[i];
		sum[get(i)] += deg[i] + 1;
	}
	for (int i = 1; i <= n; i ++ )
		printf("%.6lf\n", 1.0 * ans[get(i)] / sum[get(i)]);
}
int main(){
	LL T = 1;
	scanf("%lld", &T);
	while(T -- ){
		solve();
	}
	return 0;
}

G - Even Tree Split

题意:

\(n\) 个节点的一棵树,问删除若干条边后剩余连通块中点的数量都为偶数的方案,答案对 998244353 取模。

思路:

要保证剩余的每一块都是偶数,就将所有删除之后剩余点都是偶数的边数计算出来,记为 \(k\),答案就是 \(2^k - 1\),即所有边中取 1,2,...,\(k\) 条,不能不取,根据二项式定理容易得到答案。

代码:

#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int P = 998244353;
void solve(){
	LL n;
	cin >> n;
	vector < vector<LL> > e(n + 1);
	for (int i = 0; i < n - 1; i ++ ){
		LL u, v;
		cin >> u >> v;
		e[u].push_back(v);
		e[v].push_back(u);
	}
	LL k = 0;
	vector <LL> sz(n + 1);
	function<void(LL, LL)> dfs = [&](LL u, LL fa){
		sz[u] = 1;
		for (auto v : e[u]){
			if (v == fa) continue;
			dfs(v, u);
			sz[u] += sz[v];
		}
		if (sz[u] % 2 == 0) k ++ ;
	};
	dfs(1, 0);
	LL ans = 1;
	for (int i = 1; i < k; i ++ )
		ans = ans * 2 % P;
	cout << ans - 1 << "\n";
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	LL T = 1;
	cin >> T;
	while(T -- ){
		solve();
	}
	return 0;
}

I - Painting Game

题意:

将一张纸条分成 \(n\) 个格子,\(Alice\)\(Bob\) 轮流将格子涂黑,两个黑格子不能相邻,\(Alice\) 希望黑格子的数量尽可能少,\(Bob\) 希望黑格子的数量尽可能多,告诉你 \(n\) 以及谁先手,两人均采用最优策略,能涂多少黑格子。

思路:

纸上画画 \(n = 1, 2, ...\) 的情况,就可以推出规律来。

代码:

#include <bits/stdc++.h>
using namespace std;
#define LL long long
void solve(){
	LL n;
	string s;
	cin >> n >> s;
	LL x = ((n - 1) / 7 + 1) * 3;
	if (s == "Alice"){
		if (n % 7 == 1 || n % 7 == 2 || n % 7 == 3) cout << x - 2 << "\n";
		else if (n % 7 == 4 || n % 7 == 5) cout << x - 1 << "\n";
		else cout << x << "\n";
	}
	else{
		if (n % 7 == 1 || n % 7 == 2) cout << x - 2 << "\n";
		else if (n % 7 == 3 || n % 7 == 4) cout << x - 1 << "\n";
		else cout << x << "\n";
	}
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	LL T = 1;
	cin >> T;
	while(T -- ){
		solve();
	}
	return 0;
}
posted on 2022-08-23 18:59  Hamine  阅读(28)  评论(0编辑  收藏  举报