C - Lights Out on Tree
![alt](https://img-blog.csdnimg.cn/img_convert/2148041f78fb158a9eb27cbdba9a159d.png)
#题型/构造
分析
-
看到每次给一个点集然后保证点集大小总和的形式还以为是虚树。 -
如果一个子树内乱七八糟的颜色不统一那不管怎么翻根节点都翻不成一个颜色吧? -
所以得先统一一个子树内的颜色弄成和根节点一样再翻根节点。 -
手玩发现其实只有两种情况。考虑某个黑色的根节点,如果根节点的某一个儿子本身就是黑色,那就等这个儿子的子树全变黑了再操作;如果某一个儿子是白色,得等这个儿子的子树全变白了再翻一次这个儿子。
![alt](https://img-blog.csdnimg.cn/img_convert/63b61d3eb8e53fc02ff34cf38eaa13e2.png)
-
子树变白或者变黑的操作就放到子树那里计数,对于根节点需要新增的操作数量就是白点儿子数量 + 1(最后自己再翻一次)。 -
整个过程都可以换成 DP,所以这么做肯定操作次数最少。
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int n, Q, a[N], p[N], cnt[N];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> Q;
for(int i = 2; i <= n; i++) {
cin >> p[i];
++cnt[p[i]];
}
for(int i = 1, m; i <= Q; i++) {
cin >> m;
vector<int> arr;
int ans = 0;
for(int j = 1, v; j <= m; j++) {
cin >> v;
a[v] = 1;
arr.emplace_back(v);
ans += cnt[v] + 1;
}
for(int x : arr)
if(a[p[x]]) ans -= 2;
cout << ans << '\n';
for(int x : arr) a[x] = 0;
}
return 0;
}
D - Mod M Game
![alt](https://img-blog.csdnimg.cn/img_convert/147d1a372b2ad5f4d2c57b561431d34f.png)
#题型/博弈游戏
分析
-
容易发现如果对于每一个不同的数,出现的次数为偶数,那么肯定 Bob 胜。 -
然后就没思路了。
看题解后分析
-
考虑缩小问题结构,设 Alice 和 Bob 已经选的数和分别为 ,还剩下两个数 。如果 Alice 获胜则有 且