Codeforces Round 1028 (Div. 2) A-C
A. Gellyfish and Tricolor Pansy
题目大意
Gellyfish有a点血,他的骑士有c点血
Flower有b点血,他的其实有d点血
Gellyfish先手,每次双方的骑士都可以攻击主人或者骑士,当主人血量为0时游戏结束
问在最优策略下谁会获胜
思路
最优策略一定是攻击主人和骑士血量的最小值所在单位,二者取最小值后看谁最小,注意相等的情况下由于Gelleyfish先手,所以也是Gelleyfish赢
//Author: zengyz
//2025-06-21 15:23#include <bits/stdc++.h>using namespace std;
using i64 = long long;void solve()
{int a,b,c,d;cin>>a>>b>>c>>d;if(min(a,c)>=min(b,d)){cout<<"Gellyfish"<<endl;}else cout<<"Flower"<<endl;return;
}int main()
{ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);int _T = 1;cin >> _T;while(_T --) {solve();}return 0;
}
B. Gellyfish and Baby’s Breath
题目大意
给你两个排列p,q
对于所有i, r i = max j = 0 i ( 2 p j + 2 q i − j ) r_i=\displaystyle\max_{j=0}^i(2^{p_{j}}+2^{q_{i-j}}) ri=j=0maxi(2pj+2qi−j)
输出r从0到n-1的所有值
思路
对于 r i r_i ri来说,排列中的最大值一定是会选择的,因为以2为底的情况下两个较小值一定不会大于一个较大值
所以只需要记录排列中前i个数里的最大值以及他们的位置(用map储存)
同时比较排列p和q的情况下谁最大即可
记住这里不能使用max直接比较,因为在取模的情况下较大值可能在max的情况下反而较小
// Author: zengyz
// 2025-06-21 15:25#include <bits/stdc++.h>using namespace std;
using i64 = long long;
const int MOD = 998244353;
const int N = 1e5 + 10;
long long a[N], p[N];
long long b[N], q[N];
long long qpow[N];void solve()
{int n;cin >> n;map<long long , long long > pp, qq;for (long long i = 0; i < n; i++){cin >> p[i];if (i != 0)a[i] = max(a[i - 1], p[i]);elsea[i] = p[i];pp[p[i]] = i;}for (long long i = 0; i < n; i++){cin >> q[i];if (i != 0)b[i] = max(b[i - 1], q[i]);elseb[i] = q[i];qq[q[i]] = i;}for (long long i = 0; i < n; i++){long long ans = 0;if (a[i] > b[i])ans = (qpow[a[i]] + qpow[q[i - pp[a[i]]]]) % MOD;else if (a[i] < b[i])ans = (qpow[b[i]] + qpow[p[i - qq[b[i]]]]) % MOD;else{if (q[i - pp[a[i]]] >= p[i - qq[b[i]]])ans = (qpow[a[i]] + qpow[q[i - pp[a[i]]]]) % MOD;elseans = (qpow[b[i]] + qpow[p[i - qq[b[i]]]]) % MOD;}cout << ans << " ";}cout << endl;return;
}int main()
{ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);int _T = 1;cin >> _T;qpow[0] = 1;for (int i = 1; i <= 1e5 + 5; i++)qpow[i] = (qpow[i - 1] * 2) % MOD;while (_T--){solve();}return 0;
}
C. Gellyfish and Flaming Peony
题目大意
给定一个数组an,选取i、j(i不等于j),
可以将 a i a_i ai替换成 g c d ( a i , a j ) gcd(a_i,a_j) gcd(ai,aj)
问最少进行几次操作,可以将整个数组的值都变成相同的值
思路
1.设初始数组的最大公约数为g,对于任意一次操作,选择i,j并将 a i a_i ai替换成 g c d ( a i , a j ) gcd(a_i,a_j) gcd(ai,aj)
由于g是ai,aj的公因数,即(g|ai且a|aj)根据gcd的性质,g也必然是gcd(ai,aj)的因数,因此新数组的所有元素仍能被g整除,最大公约数仍为g,所以每次操作后,数组的gcd始终保持为g
当所有元素变为同一个数 x 时,数组的 gcd 即为 x。由于操作过程中 gcd 始终为 g,故 (x = g)。
2.每次操作将 (a_i) 替换为 (gcd(a_i, a_j)),而 gcd 的结果一定是 (a_i) 和 (a_j) 的公因数。因此,经过若干次操作后,每个元素 (a_i) 必然是初始所有元素的公因数(因为每次操作只会保留或缩小因数)。
若最终所有元素为 x,则 x 必须是所有初始元素的公因数,即 (x | a_i) 对所有 i 成立。x 与最大公约数 g 的关系
由于 g 是所有 (a_i) 的最大公约数,因此所有公因数 x 必然满足 (x|g)(即 x 是 g 的因数)。但结合 “操作不改变 gcd” 的结论,当所有元素为 x 时,数组的 gcd 为 x,而初始 gcd 为 g,故 (x = g)。
换句话说
假设最后所有数都是 x,那么 x 必须是所有数的公因数(因为每次操作后的数都是之前数的公因数),而 g 是最大的公因数,所以 x 不能超过 g。但所有数都是 g 的倍数,所以 x 至少是 g(比如 x=2,而 g=2),因此 x 只能等于 g。
所以我们使用vector排序去重后,用多源bfs遍历可能的结果,用Dist记录步数,最后的答案就是n+dist(变成这个数最少需要几步)
// Author: zengyz
// 2025-06-21 16:43#include <bits/stdc++.h>using namespace std;
using i64 = long long;int gcd(int a, int b)
{if (b == 0)return a;return gcd(b, a % b);
}void solve()
{int n;cin >> n;vector<int> a(n);for (auto &x : a)cin >> x;int tar = a[0];for (int i = 1; i < a.size(); i++)tar = gcd(tar, a[i]);int cnt = 0;for (int i = 0; i < a.size(); i++)if (a[i] == tar)cnt++;if (cnt){cout << n - cnt << endl;return;}vector<int> b = a;sort(b.begin(), b.end());b.erase(unique(b.begin(), b.end()), b.end());queue<int> q;vector<int> dist(5090, 1e9);for (int i = 0; i < b.size(); i++){q.push(b[i]);dist[b[i]] = 0;}while (!q.empty()){int u = q.front();q.pop();for (int i = 0; i < b.size(); i++){int v = b[i];int t = gcd(u, v);if (t == tar){cout << n + dist[u] << endl;return;}if (dist[t] > dist[u] + 1){dist[t] = dist[u] + 1;q.push(t);}}}return;
}int main()
{ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);int _T = 1;cin >> _T;while (_T--){solve();}return 0;
}