A. Binary Matrix
题意:给你一个\(01\)矩阵,你要修改尽量少的位置,使得每行每列的异或和都是\(0\)。
有三种修改方式:
- 修改一个位置使得一行一列满足
- 对于两个不满足条件的行,分别修改同一列的位置,使得两个行满足。
- 对于两个不满足条件的列,分别修改同一行的位置,使得两个列满足。
发现行或者列自己修改都是消耗两次操作,第一种操作只要一次操作就能使得一行一列满足条件,那么先进行第一次操作,使得行都满足条件或者列都满足条件,这是剩下的就只需要进行第二个操作或者第三个操作。分析发现操作数就是行不满足条件的个数和列不满足条件的个数的最大值。
点击查看代码
void solve() {int n, m;std::cin >> n >> m;std::vector<std::string> s(n);for (int i = 0; i < n; ++ i) {std::cin >> s[i];}int ansr = 0;for (int i = 0; i < n; ++ i) {int cnt = std::count(s[i].begin(), s[i].end(), '1');ansr += cnt & 1;}int ansc = 0;for (int j = 0; j < m; ++ j) {int cnt = 0;for (int i = 0; i < n; ++ i) {cnt += s[i][j] == '1';}ansc += cnt & 1;}std::cout << std::max(ansr, ansc) << "\n";
}
B. Floor or Ceil
题意:给你一个\(x\),你要进行\(n\)次除二向下取整操作和\(m\)次除二向上取整操作。问所有操作里的最小值和最大值。
发现两个操作只有在当前数是不是奇数的情况下才有差别。要想得到最小值,应该先把所有向上取整的操作用完,在向下取整,因为每次遇到一个奇数,向上取整都会是值大一,不妨让它一直操作完,这样到最后向下取整能最小化值,比如如果先向下取整可能得到1,然后向上取整就一直保持这个1,但如果先向上取整,那么向下取整就能把这个1除成0。同样分析可以分析最大值是先向下取整,然后向上取整。
点击查看代码
void solve() {int x, n, m;std::cin >> x >> n >> m;int min = x, a = n, b = m;while (min > 1 && b -- ) {min = (min + 1) / 2;}while (min && a -- ) {min /= 2;}int max = x;a = n, b = m;while (max && a -- ) {max /= 2;}while (max > 1 && b -- ) {max = (max + 1) / 2;}std::cout << min << " " << max << "\n";
}
C. Math Division
题意:给你一个二进制串,每次有\(\frac{1}{2}\)的概率进行向下取整或者向上取整。求变成\(1\)的操作次数的期望。
首先要发现,操作次数只有\(n\)和\(n-1\)两种,其中\(n\)次操作是有一次向上取整使得位数不变。比如\(11\)向下取整是\(1\),向上取整是\(10\)。那么我们需要求出\(n\)次操作的情况。
其实向上取整就是末尾为1的情况可以进行进位。
那么我们需要知道第\(2\)位进位的概率(位数从高到低)。需要知道第\(2\)位进位的概率就需要知道第\(3\)位的概率,分析下去发现这是一个递推式,我们要用\(dp\)解决。
设\(f_i\)为第\(i\)位进位的概率。对于第\(i\)位,如果是\(0\),那么它要进位需要第\(i+1\)位进位,那么概率是\(f_i = \frac{1}{2} \times f_{i+1}\),如果第\(i\)位是\(1\),那么第\(i+1\)位如果进位则不管第\(i\)位是什么操作都会往前进位,或者第\(i+1\)位不进位,那么第\(i\)位需要进位,则\(f_i = \frac{1}{2} \times (1 - f_{i+1}) + f_{i+1}\)。
那么我们把\(f\)看作多进行一次操作的概率,则答案为\(n-1+ f_2\)。因为设进行\(n-1\)操作的概率为\(x\),进行\(y\)次操作的概率为\(y\),则答案为\((n-1)\times x + n \times y\),这个式子等于\((n - 1) \times x + (n - 1 + 1) \times y => n - 1 + y\)。
点击查看代码
void solve() {int n;std::cin >> n;std::string s; std::cin >> s;Z ans = 0;for (int i = n - 1; i > 0; -- i) {if (s[i] == '0') {ans = ans / 2;} else {ans = (1 - ans) / 2 + ans;}}std::cout << (n - 1 + ans) << "\n";
}