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}\)

那么我们现在就可以用二项式定理来化简了,最后的结果是:

\[\cfrac{\sum_{i=0}^{n\times m} C_{n\times m}^{i}\times (-odd)^i \times even^{n\times m -i}\times+\sum_{i=0}^{n\times m} C_{n\times m}^{i}\times odd^i \times even^{n\times m -i}}{2} \]

\[=\cfrac{(-odd+even)^{n\times m}+(odd+even)^{n\times m}}{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;
}
posted @ 2025-02-19 00:10  KS_Fszha  阅读(20)  评论(0)    收藏  举报