Codeforces Round #630 (Div. 2)
A
切的有点慢…A题居然这么长…
单独处理一下一条缝的情况,此时不能进行任何该垂直方向上的移动。
B
切的更慢了…没有快速察觉到合数…
因为合数所以至少有两个因子,且这个合数不超过1000,那么其中一个因子一定不超过
1000
\sqrt{1000}
1000,约等于31.6,而31恰为第11个素数,那么对于所有不超过1000的数一定会要包含前11个素数中的1个,然后记录一下个数和所属情况对应输出即可。
C
容易证明k完全的大回文串的充分必要条件为每段k串均为相同的小回文串,充分性显然,必要性可以采用反证法。之后对k串的每一对对称位(即第i
位和第n - 1 - i
位)进行考虑,找出所有k串中这两个位置上出现最多的字母,用该字母覆盖这两位上所有的不同的旧字母显然最优。注意特判一下i == n - 1 - k
的情况。
D
构造题。
因为bob的算法仅仅考虑了数字最大,而没有考虑位1之间的关系,所以bob的算法一定不会大于答案。题目要求差值为k,为了简便,我们不妨尝试构造bob的答案为0,真答案为k的情况。记k的最高位为wei
,如果能够让bob因为一个高位的1而障目,就忽视了更低位的0,那么我们就可以完成目的。可以将[00]置为k | (1 << wei + 1)
,[01]置为1 << wei + 1
, [10][11]置为(1 << wei + 1) - 1
,那么bob就会因为高位的1将dp值变为10000…,而忽视了正确的01111…,最后在答案处成为0。我写的时候用33矩阵,更简洁的22矩阵应该也没问题。
补题
E
与其说是补题…不如说是重看一遍题目…
题目要求的是初始值在[L, R]
之间,我晚上以为是操作之后也要保持在该区间内(那还咋做qwq)…
如果只有初始值的约束就简单了…容易发现操作只可以对奇数、偶数的个数进行偶数次的变化,只有当整个棋盘的奇偶性全部相同才能同高度。那么,如果
- nm为奇数: 无论有什么奇偶性的偶数,一定有另一奇偶性的奇数。所以无论怎么选取,偶数个的一类数一定可以通过若干次操作全部成为另一类,因而此时种数即为 ( R − L + 1 ) n m (R - L + 1)^{nm} (R−L+1)nm
- nm为偶数: 只有当奇数偶数均为偶数个时,整个棋盘才可能变换得到奇偶性全部相同的情况。那么由组合数学容易得到计数表达式:
∑
i
为
偶
数
,
0
≤
i
≤
n
m
C
n
m
i
a
i
b
n
m
−
i
\sum_{i为偶数,0≤i≤nm}C_{nm}^ia^ib^{nm-i}
∑i为偶数,0≤i≤nmCnmiaibnm−i,其中a是区间
[L, R]
中偶数的个数,b是[L, R]
中奇数的个数,a与b都是常数。考虑二项式生成函数 ( a + b ) n m (a + b)^{nm} (a+b)nm和 ( − a + b ) m n (-a + b)^{mn} (−a+b)mn,求和除以2就是所有的偶数二项式单项式之和。
求ab的值费了点劲…而且还是写的很丑…因为在C++中运算/
不是真正的底函数,而是向0
取整的"底函数"…
虽然无伤大雅但是纯数学表达式如果弄的不优美就很难受…
小坑点
以前写带取模的quick_pow
喜欢把qp的返回值设成int,但是如果在代码中qp不是作为一个最终结果而还要进行其他运算时,int与int之间的运算就有可能会爆范围,这里以后要注意!
const int M = 998244353;
ll qp(ll a, ll p){
ll res = a, ans = 1;
while(p){
if(p & 1) ans = ans * res % M;
res = res * res % M;
p >>= 1;
}
return (ans % M + M) % M;
}
int main(){
// Fast;
ll n, m, L, R; scanf("%lld %lld %lld %lld", &n, &m, &L, &R);
n *= m;
ll a, b;
if(L & 1){
if(L == R) a = 0;
else a = (R - L - 1) / 2 + 1;
}
else a = (R - L) / 2 + 1;
b = R - L + 1 - a;
ll ans;
if(n % 2 == 0){
ans = (qp(a + b, n) + qp(-a + b, n)) % M * qp(2, M - 2);
ans = (ans % M + M) % M;
}
else ans = qp(R - L + 1, n);
printf("%lld\n", ans);
return 0;
}