[codeforces 1332E] Height All the Same 奇偶构造+排列组合+快速幂+二项式定理+乘法逆元

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

ProblemLangVerdictTimeMemory
E - Height All the Same GNU C++11Accepted31 ms100 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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值