Codeforces 1332E Height All the Same [ 紫 ] [ 组合数学 ] [ 二项式定理 ]
Height All the Same:小清新二项式定理题。话说这玩意真的有紫吗,不管是推式子部分还是观察部分都比较显然吧,感觉可以蓝。
转化
首先看到每次进行 \(1,2\) 的增加,不难联想到奇数和偶数的性质。我们以 \(2\) 为粒度变化,操作 \(1\) 就相当于给网格中相邻两个格子的奇偶性发生改变,而操作 \(2\) 是在所有的格子奇偶性相同的时候把网格图的所有数字变得相等的。所以本题中只有操作 \(1\) 的改变相邻两个格子的奇偶性的操作是有用的,并且我们可以由此转化为网格上的 \(0,1\) 问题(按照奇偶性)。
观察
那么操作 \(1\) 有啥性质呢?不难发现,假设相邻的两个有一个 \(0\) 和一个 \(1\),那么我们执行操作,就相当于把这个 \(1\) 进行了一次上下左右的移动,\(0\) 也是同理的。而如果操作的两个数奇偶性相同,那么执行操作后奇偶性还是相同,就相当于没有用。
也就是说,我们要消除 \(1\),让它全变 \(0\);或者要消除 \(0\),让它全变 \(1\)。
消除该如何做呢?显然是将两个本来不挨在一起的两个 \(0\) 或 \(1\) 通过操作 \(1\) 挨在一起,然后再对这个两个数执行一次操作 \(1\),就能起到消除这两个 \(0\) 或 \(1\) 的效果。因为是两两相消的,所以要消除的数字必须出现偶数次。
但到底要消除 \(0\) 还是消除 \(1\) 呢?这个我们就要分讨了。
当 \(n\times m\) 为奇数时
显然填什么数都合法,因为奇数要拆分成奇数和偶数,而 \(0\) 和 \(1\) 的个数在 \(n\times m\) 为奇数的情况下不可能同奇偶性,必然存在 \(0\) 或 \(1\) 满足个数为偶数的要求,所以所有状态都合法,答案为 \((r-l+1)^{n\times m}\)。
当 \(n\times m\) 为偶数时
这时候就不是填啥都合法了,因为 \(0,1\) 的个数同奇偶性,所以 \(0,1\) 的个数都必须是偶数才能两两消除完。
假设 \([l,r]\) 中的奇数个数为 \(odd\),偶数个数为 \(even\)。
那么这时候的答案是 \(\sum_{i \bmod 2 =0} C_{n\times m}^{i}\times odd^i \times even^{n\times m -i}\)。暴力计算显然会超时。
观察到式子只对偶数项求和,并且还有组合数,很容易想到用二项式来加速计算。所以我们考虑对所有项求和,然后把奇数项乘一个 \(-1\),最后将结果再加上所有项的和,就是偶数项的两倍了。因为奇数项全部被抵消了。
这个结果式子就是 \(\cfrac{\sum_{i=0}^{n\times m} C_{n\times m}^{i}\times odd^i \times even^{n\times m -i}\times (-1)^i+\sum_{i=0}^{n\times m} C_{n\times m}^{i}\times odd^i \times even^{n\times m -i}}{2}\)。
那么我们现在就可以用二项式定理来化简了,最后的结果是:
快速幂计算即可,时间复杂度 \(O(\log n\times m)\)。
代码
#include <bits/stdc++.h>
#define fi first
#define se second
#define eb(x) emplace_back(x)
#define pb(x) push_back(x)
#define lc(x) (tr[x].ls)
#define rc(x) (tr[x].rs)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
using pi=pair<int,int>;
const ll mod=998244353;
ll n,m,l,r;
ll qpow(ll a,ll b)
{
ll res=1;
while(b)
{
if(b&1)res=(res*a)%mod;
b>>=1;
a=(a*a)%mod;
}
return res;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>m>>l>>r;
ll odd=(r+1)/2-(l-1+1)/2,even=r/2-(l-1)/2;
if((1ll*n*m)&1)cout<<qpow(r-l+1,1ll*n*m);
else cout<<(qpow(even-odd,1ll*n*m)+qpow(even+odd,1ll*n*m))%mod*qpow(2,mod-2)%mod;
return 0;
}

浙公网安备 33010602011771号