Codeforces Round #630 (Div. 2)
题目链接:https://codeforces.com/contest/1332
A - Exercising Walk
贪心一下。
B - Composite Coloring
题意:给若干个1000以内的合数,把他们染成若干种颜色,使得两个相同颜色的数字的gcd都不为1。输出答案时,要求输出使用的颜色数m,且恰好用[1,m]中每种颜色至少1次。
题解:1000以内的合数的质因数恰好有11种,每种质数就把其倍数全部染色,最后把颜色离散化到[1,m]。
C - K-Complete Word
题意:给一个长度为n的字符串,和n的一个因数k。定义一个字符串是“k完全的”,当其由长度为k的n/k个完全相同的回文串拼接形成(也就是说周期也是k)。修改一个字符的消耗是1,求最小的消耗使得这个字符串变为“k完全的”。
题解:某些对应位置的字符是要求完全相同的,包括回文和周期两方面的影响,把这些位置的字符数量统计出来,然后保留最多的一种,其他的往最多的变。贪心。
D - Walk on Matrix
题意:假如有一个n*m的数字矩阵,那么要求从左上角(1,1)走到右下角(n,m),每次只能往右走或者往下走,把路径上的数字全部“按位与”就得到一个结果。求所有路径中的结果的最大值,记为A。有个逗B弄了一个假算法,假算法是这样的:
把假算法的结果记为B。
给一个数字k<=1e5,构造一个不超过500*500的矩阵,矩阵中的元素不超过3e5,使得A和B的差值恰好为k。
题解:首先要观察这个假算法假在哪里:假在max运算有可能会保留高位而抛弃低位,而高位最后会因为“按位与”而不能保留,恰好低位可以暴力,就会出错。那么正确的算法很简单:贪心,从高位开始逐位验证该位是否存在一条全1的路径使得该位可以保留1,若可以,则该位必定是1,且后续选择的路径必须在这些全1路径中选。换言之,就是先取第1位,看看是否有一条全1的路,若有,则验证是否有第1位和第2位都是1的路,若还有,则验证是否有第1位和第2位和第3位都是1的路,直到某位不可以是1,那么这位必须是0,复杂度是O(nmlog)。
回到这个题目,显然A>=B,不妨设A=B+k,按常理一般看看是否可以使得B=0,这时A最大要到k,也挺符合构造的。根据上面的观察,推测是否可以构造一个最高位来欺骗假算法走错,恰好可以构造p17=(1<<17)这个数,这个数首先与[1,1e5]的二进制位都没有冲突,加上k也不超过3e5。
构造了很久,最后发现:
| p17+k | k | p17 |
| p17 | p17+k | k |
这个矩阵会诱导假算法保留p17。
E - Height All the Same
题意:假设有一个n*m的平面矩阵,上面每个格子有一些方块,有两种操作,第1种操作是给连续的两个格子都放1个方块,第2种操作是给同一个格子放2个方块,给出这个平面矩阵的初始状态,问是否可以把这个平面矩阵变得一样高。(上次想要的那个A题来了)
对所有的n*m的平面矩阵,每个元素都在[L,R]自由取值,统计可以变得一样高的平面矩阵的数目。
题解:
- 推论:由于第2种操作的存在,可以把值全部模2。
证明:记最大值为M,那么其他值都可以通过第2种操作加到M-1或者M。
问题变成:给一个n*m的平面矩阵,元素都是0或者1,第1种操作变为给连续的两个格子同时翻转,求是否可以把整个矩阵变成全0或者全1。
- 推论:可以同时翻转任意两个格子,不需要连续。
证明:选择想要翻转的两个格子,然后连接他们有一条路,对路上的格子依次进行第1种操作,最后只有首尾的格子受到影响,中间的格子恰好都经过两次第1种操作抵消了。
问题变成:给一个n*m的平面矩阵,元素都是0或者1,操作是给任意两个格子同时翻转,求是否可以把整个矩阵变成全0或者全1。
- 推论:n*m为奇数个格子必定有解。
证明:由推论2可以知道,可以无限制给元素总和+2或者-2,不改变其奇偶性,总是可以变成全0或者全1。
- 推论:n*m为偶数个格子,若元素总和为偶数必定有解,若元素总和为奇数必定无解。
证明:同上
- 推论:区间[L,R]可以平移为区间[0,R-L],为方便可以记k=R-L。
证明:n*m为偶数个格子的时候,可以经过铺一层第1种操作强行把每个格子的奇偶性翻转,所以可以偶数个格子的情况可以对取值区间进行平移。
题解:那么给n*m的值分类讨论,假如是奇数那么直接快速幂。否则前n*m-1个格子可以任选,最后一个格子要视情况补回奇偶性。
统计这个东西的时候却不会统计,看官方题解:
Let's find out the number of ways to choose the grid such that the number of even cells is even and \(0 \le a_i \le k\).
Suppose that there are \(E\) even numbers in \([0,k]\), \(O\) odds. Therefore, for any given \(0 \le i \le nm\), the number of ways to have exactly \(i\) even numbers should be \(E^i O^{nm-i} \times \binom{nm}{i}\). Thus, the total answer should be \(\sum \limits_{i=0}^{nm/2} E^{2i} O^{nm-2i} \binom{nm}{2i}\), which should remind you of the Newton expansion.
Note that
\((E+O)^{nm}=\sum_{i=0}^{nm/2}E^{2i}O^{nm-2i}\binom{nm}{2i}+\sum_{i=1}^{nm/2}E^{2i-1} O^{nm-(2i-1)} \binom{nm}{2i-1}\)
and
\((E-O)^{nm}=\sum_{i=0}^{nm/2}E^{2i}O^{nm-2i}\binom{nm}{2i}-\sum_{i=1}^{nm/2}E^{2i-1} O^{nm-(2i-1)} \binom{nm}{2i-1}\)
.
Adding those two formulas will get us exactly the formula we were looking for but doubled. Thus, the answer is that divided by \(2\).
这个什么东西来的啊。(其实是二项式定理)
启发:类似这种 \(C_{n}^{i}a^{i}b^{n-i}\) 形式的求和,假如i是只取奇数或者只取偶数,可以巧妙构造二项式定理来求解。
const ll MOD = 998244353ll;
ll qpow(ll x, ll n) {
//这里并不需要操作指数,就算操作指数也最好使用扩展欧拉定理
//扩展欧拉定理可以避免0^0也返回1的情况,会正确返回0
//n = n % (MOD - 1ll) + (MOD - 1ll);
ll res = 1ll;
while(n) {
if(n & (1ll))
res = res * x % MOD;
x = x * x % MOD;
n >>= 1;
}
return res;
}
void TestCase() {
ll n, m, L, R;
scanf("%lld%lld%lld%lld", &n, &m, &L, &R);
if(n * m % 2 == 1) {
ll ans = qpow(R - L + 1ll, n * m);
printf("%lld\n", ans);
return;
} else {
ll O = (R - L + 1ll) / 2ll;
ll E = (R - L + 1ll) - O;
ll tmp1 = qpow(O + E, n * m);
ll tmp2 = qpow(O - E, n * m);
ll ans = (tmp1 + tmp2) * qpow(2ll, MOD - 2ll) % MOD;
printf("%lld\n", ans);
return;
}
}
提示:通常写的快速幂算法要求指数不为0,这样会使得res至少叠加上一次x从而返回正确的结果,而一般情况下若指数为0,底数不为0,结果也是正确的1。
也就是说,快速幂算法在指数为0的情况出现某种特例:没有给res一开始就取MOD,有可能导致溢出。
在底数为0,且指数也为0的情况,会出现另一种特例:没有给res叠加一个0,导致返回1。
问题在于0的正整数次幂应该为0,这时快速幂算法可能会出错,意思是快速幂的时候最好特判一下底数的情况。尤其小心在使用欧拉定理之后可能导致指数为0的情况,假如不管发生什么都强行把指数+PHIMOD(扩展欧拉定理)就可以避免指数过小的情况。