Codeforces Round #630 (Div. 2) 比赛人数12012
[codeforces 1332E] Height All the Same 奇偶构造+排列组合+快速幂+二项式定理+乘法逆元
总目录详见https://blog.csdn.net/mrcrack/article/details/103564004
在线测评地址https://codeforces.com/contest/1332/problem/E
Problem | Lang | Verdict | Time | Memory |
---|---|---|---|---|
E - Height All the Same | GNU C++11 | Accepted | 31 ms | 100 KB |
1.题意理解
如何摆放方块,题意的理解也是很大的问题。
stack up one cube in two adjacent cells;此句如何理解,根据下图中的Operation 1还是很难理解。
这个时候需要的是耐心,还是要抓关键字眼。
Initially ai,j cubes are stacked up in the cell (i,j).这一句很关键,cell界定的是位置,同一个cell里可以摆放很多个cubes。
将上面两句英文与图结合,应该就能读懂题意:
现在有一个n∗m的方格,第i行第j列有a[i][j]个方块。
你可以执行以下操作任意次:
1.1、选择(i,j)使a[i][j]加上2。
1.2、选择两个相邻的格子,将其方块数各加上1。
现在问初始a[i][j]可以是[L,R]中的任意数,有多少种初始方案可以通过任意次数的操作后使所有的a[i][j]相等。
2.思路摘自https://www.cnblogs.com/qieqiemin/p/12614527.html更正了个别错误
2.1因为 Operation 2 不改变奇偶性,而同奇偶性的数一定可以通过 Operation 2 变成相等的数,所以对于一个n∗m
的格子,只考虑其奇偶性,问题可以转化为,能否选择两个相邻的格子,使其奇偶性翻转,最后使整个格子奇偶性一致。
这是一个经典的问题,解法为:奇数和偶数的个数全部都是奇数是不行的,否则可行。
可以观看下图,红色代表奇数,白色代表偶数。
我们可以通过一次翻转( Operation 1 )使其变成:
当将奇数移动到一些特殊的位置后,有因为剩下的偶数的个数cnt为偶数,可以通过cnt/2次翻转操作( Operation 1 )变为:
全部变成红色(奇数),上图中的1代表第1次操作,2代表第2次操作,3代表第3次操作,4代表第4次操作。
只要奇数的个数和偶数个数的至少一个为偶数,就可以通过这种方法将其变成同奇偶性。
(R-L+1)^nm解释如下:每个位置都可以取值如下
L,L+1,L+2,......,R-1,R,共有R-L+1种取法,总共有nm个位置,根据排列组合的乘法原理,种类数是(R-L+1)^nm
2.2否则,此时n∗m是偶数,设a为[L,R]中奇数的个数,设b为[L,R]中偶数的个数。
若掌握了二项式定理,上式最右的等式应能看懂。
2.3.a+b=R-L+1
若R-L+1是奇数,|a-b|=1;若R-L+1是偶数,|a-b|=0.
可以这样举例研究|a-b|取值由来:
1,2,3,4,5中有2个偶数,3个奇数,R-L+1=5,|a-b|=1
1,2,3,4,5,6中有3个偶数,3个奇数,R-L+1=6,|a-b|=0
2,3,4,5,6中有3个偶数,2个奇数,R-L+1=5,|a-b|=1
2,3,4,5,6,7中有3个偶数,3个奇数,R-L+1=6,|a-b|=0
2.4.别忘了计算2的乘法逆元。
AC代码如下
#include <stdio.h>
#define LL long long
#define mod 998244353
LL quick_pow(LL a,LL b){//快速幂
LL ans=1;
while(b){
if(b&1)ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
int main(){
LL n,m,L,R,x,ans;
scanf("%lld%lld%lld%lld",&n,&m,&L,&R);
x=R-L+1;
if(n*m%2==1)printf("%lld\n",quick_pow(x,n*m));
else{//n*m%2==0
//a奇数个数,b偶数个数 a+b=R-L+1, |a-b|=1或0,若R-L+1奇数,为1,否则为0
ans=quick_pow(x,n*m)+((x&1)?1:0);//((x&1)?1:0)计算(a-b)^nm
ans=ans*quick_pow(2,mod-2)%mod;//关于2的乘法逆元
printf("%lld\n",ans);
}
return 0;
}