比赛链接:
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;
}