C
一开始没有读懂题意,以为是轮流游戏,看别人翻译才发现先手在下一轮会变为反手,导致搞了半天过不了样例。
可以知道如果\(n\)这张牌在Alice手中,则Alice先手打出这张牌必胜。
如果\(n\)这张牌不在Alice手中:
1.\(n-1\)这张牌在Alice手中,那么可以打出\(n-1\)这张牌,Bob相应打出\(n\)这张牌,转化为\(n-2\)时的问题。
2.\(n-1\)这张牌在Bob手中,那么Bob只需要先打出\(n-1\),再先手打出\(n\)即可必胜。
设有\(i\)(\(i\)为偶数)张牌时Alice先手获胜的方案数为\(f_i\),后手获胜的方案数为\(g_i\),
那么有递推方程:
\(f_i = C(i - 1, i / 2 - 1) + g_{i-2}\)
\(g_i = C(i - 2, i / 2 - 2) + f_{i-2}\)
平局的方案仅有一种:Alice手中的牌大小都为奇数,Bob手中的牌大小全为偶数。
void solve() {
ll n; cin >> n;
ll a = 0, b = 0, cnt = 1;
for (int i = n;i > 2;i -= 2) {
if (cnt & 1) a = (a + C(i - 1, i / 2 - 1)) % mod;
else a = (a + C(i - 2, i / 2 - 2)) % mod;
cnt ++;
}
if (cnt & 1) a = (a + 1) % mod;
b = C(n, n / 2) - a - 1;
cout << a << ' ' << (b + mod) % mod << " 1\n";
}
E
给定一颗有\(n\)个结点的有根树,\(1\)号结点为根结点,至多进行\(k\)次操作。
每次操作可以把一棵子树的父亲结点接到\(1\)号点,作为\(1\)号结点的儿子。
问树的深度最小是多少?
(二分答案 + 贪心)
二分答案\(mid\)之后,从下往上记录深度,如果一个结点的深度等于\(mid-1\),但他的父亲不是\(1\)号结点,则至少需要一次操作将其接到\(1\)号结点以满足深度不超过\(mid\)的要求。
void solve() {
int n, k, cnt = 0; cin >> n >> k;
vector<int> g[n + 1], f(n + 1);
for (int i = 2;i <= n;i++) {
int p; cin >> p;
f[i] = p;
g[p].pb(i);
}
function<int(int, int)> dfs = [&](int x, int m) {
int h = 1;
for (auto y : g[x]) {
h = max(h, dfs(y, m) + 1);
}
if (h == m && f[x] > 1) {
//cout << x << endl;
cnt ++;
h = 0;
}
return h;
};
auto check = [&](int x) {
cnt = 0;
dfs(1, x);
return cnt > k ? false : true;
};
int l = 1, r = n + 1;
while (l < r) {
int mid = (l + r) >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
cout << r << endl;
}
标签:结点,int,mid,Educational,张牌,Codeforces,136,cnt,Alice
From: https://www.cnblogs.com/coldarra/p/16754125.html