Gym103960B Fun with Stones

并不是多困难或者有趣的题,写sol仅仅是因为觉得好笑()。

题目大意

三堆石子 Nim 游戏,第 i i i 堆石子数量在 [ l i , r i ] [l_i , r_i] [li,ri] 中随机,求先手必胜的概率,对 1 0 9 + 7 10^9+7 109+7 取模。

l i , r i ≤ 1 0 9 l_i , r_i≤10^9 li,ri109

题解

说人话就是求三个数异或起来不为0的概率,很容易想到数位dp,由于只有三个数,硬求就好了。

那么为什么我上面写到 “觉得好笑” 呢。

因为听说有个很高妙的写法十几分钟就可以写完,可我是sb我不会,然后很正经地写了个27类巨大分讨6k数位dp,更好笑的是写完居然一遍过了()。事后知道有高妙写法的我:(iДi) 。

还是大概说一下,先算出异或和为0的方案数最后减一下除以总数即可。区间比较难求那就dp求出范围分别小于 x , y , z x,y,z x,y,z 的然后容斥一下即可。dp具体实现就是 f i , 0 / 1 , 0 / 1 , 0 / 1 f_{i,0/1,0/1,0/1} fi,0/1,0/1,0/1 ,代表现在考虑到第 i i i 位、第一个数是否顶着上界、第二个数是否顶着上界、第三个数是否顶着上界的方案数。转移时分别枚举三个数在这一位上是 0/1,三个数的当前位置分别和上界当前位置比较大小再自己算一下这一位可以从哪些状态转移过来即可。

复杂度也许是 l o g log log 带巨大常数,总之能过。

Code

写得很蠢,但是因为很好笑所以还是贴上来吧,就当看个乐子。

#include<bits/stdc++.h>
using namespace std;
 
const int N=35,mod=1e9+7;
 
int l1,r1,l2,r2,l3,r3,ans,f[N][2][2][2];
 
int solve(int x,int a,int a1,int b,int b1,int c,int c1){
	int res=0;
	for(int i=a;i<=a1;i++)
		for(int j=b;j<=b1;j++)
			for(int k=c;k<=c1;k++)
				res=(res+f[x][i][j][k])%mod;
	return res;
}
 
int work(int a,int b,int c){
	memset(f,0,sizeof(f));
	f[32][1][1][1]=1;
	for(int i=31,x,y,z;i>=0;i--){
		x=((a>>i)&1),y=((b>>i)&1),z=((c>>i)&1);
		for(int a1=0;a1<=1;a1++)
			for(int b1=0;b1<=1;b1++)
				for(int c1=0;c1<=1;c1++){
					if((a1^b1^c1)!=0) continue;
					if(a1<x){
						if(b1<y){
							if(c1<z) f[i][0][0][0]=(f[i][0][0][0]+solve(i+1,0,1,0,1,0,1))%mod;
							else if(c1==z){
								f[i][0][0][0]=(f[i][0][0][0]+solve(i+1,0,1,0,1,0,0))%mod;
								f[i][0][0][1]=(f[i][0][0][1]+solve(i+1,0,1,0,1,1,1))%mod;
							}
							else f[i][0][0][0]=(f[i][0][0][0]+solve(i+1,0,1,0,1,0,0))%mod;
						}
						else if(b1==y){
							if(c1<z){
								f[i][0][0][0]=(f[i][0][0][0]+solve(i+1,0,1,0,0,0,1))%mod;
								f[i][0][1][0]=(f[i][0][1][0]+solve(i+1,0,1,1,1,0,1))%mod;
							}
							else if(c1==z){
								f[i][0][0][0]=(f[i][0][0][0]+solve(i+1,0,1,0,0,0,0))%mod;
								f[i][0][1][0]=(f[i][0][1][0]+solve(i+1,0,1,1,1,0,0))%mod;
								f[i][0][0][1]=(f[i][0][0][1]+solve(i+1,0,1,0,0,1,1))%mod;
								f[i][0][1][1]=(f[i][0][1][1]+solve(i+1,0,1,1,1,1,1))%mod;
							}
							else{
								f[i][0][0][0]=(f[i][0][0][0]+solve(i+1,0,1,0,0,0,0))%mod;
								f[i][0][1][0]=(f[i][0][1][0]+solve(i+1,0,1,1,1,0,0))%mod;
							}
						}
						else{
							if(c1<z) f[i][0][0][0]=(f[i][0][0][0]+solve(i+1,0,1,0,0,0,1))%mod;
							else if(c1==z){
								f[i][0][0][0]=(f[i][0][0][0]+solve(i+1,0,1,0,0,0,0))%mod;
								f[i][0][0][1]=(f[i][0][0][1]+solve(i+1,0,1,0,0,1,1))%mod;
							}
							else f[i][0][0][0]=(f[i][0][0][0]+solve(i+1,0,1,0,0,0,0))%mod;
						}
					}
					else if(a1==x){
						if(b1<y){
							if(c1<z){
								f[i][0][0][0]=(f[i][0][0][0]+solve(i+1,0,0,0,1,0,1))%mod;
								f[i][1][0][0]=(f[i][1][0][0]+solve(i+1,1,1,0,1,0,1))%mod;
							}
							else if(c1==z){
								f[i][0][0][0]=(f[i][0][0][0]+solve(i+1,0,0,0,1,0,0))%mod;
								f[i][0][0][1]=(f[i][0][0][1]+solve(i+1,0,0,0,1,1,1))%mod;
								f[i][1][0][0]=(f[i][1][0][0]+solve(i+1,1,1,0,1,0,0))%mod;
								f[i][1][0][1]=(f[i][1][0][1]+solve(i+1,1,1,0,1,1,1))%mod;
							}
							else{
								f[i][0][0][0]=(f[i][0][0][0]+solve(i+1,0,0,0,1,0,0))%mod;
								f[i][1][0][0]=(f[i][1][0][0]+solve(i+1,1,1,0,1,0,0))%mod;
							}
						}
						else if(b1==y){
							if(c1<z){
								f[i][0][0][0]=(f[i][0][0][0]+solve(i+1,0,0,0,0,0,1))%mod;
								f[i][0][1][0]=(f[i][0][1][0]+solve(i+1,0,0,1,1,0,1))%mod;
								f[i][1][0][0]=(f[i][1][0][0]+solve(i+1,1,1,0,0,0,1))%mod;
								f[i][1][1][0]=(f[i][1][1][0]+solve(i+1,1,1,1,1,0,1))%mod;
							}
							else if(c1==z){
								f[i][0][0][0]=(f[i][0][0][0]+solve(i+1,0,0,0,0,0,0))%mod;
								f[i][0][1][0]=(f[i][0][1][0]+solve(i+1,0,0,1,1,0,0))%mod;
								f[i][0][0][1]=(f[i][0][0][1]+solve(i+1,0,0,0,0,1,1))%mod;
								f[i][0][1][1]=(f[i][0][1][1]+solve(i+1,0,0,1,1,1,1))%mod;
								f[i][1][0][0]=(f[i][1][0][0]+solve(i+1,1,1,0,0,0,0))%mod;
								f[i][1][1][0]=(f[i][1][1][0]+solve(i+1,1,1,1,1,0,0))%mod;
								f[i][1][0][1]=(f[i][1][0][1]+solve(i+1,1,1,0,0,1,1))%mod;
								f[i][1][1][1]=(f[i][1][1][1]+solve(i+1,1,1,1,1,1,1))%mod;
							}
							else{
								f[i][0][0][0]=(f[i][0][0][0]+solve(i+1,0,0,0,0,0,0))%mod;
								f[i][0][1][0]=(f[i][0][1][0]+solve(i+1,0,0,1,1,0,0))%mod;
								f[i][1][0][0]=(f[i][1][0][0]+solve(i+1,1,1,0,0,0,0))%mod;
								f[i][1][1][0]=(f[i][1][1][0]+solve(i+1,1,1,1,1,0,0))%mod;
							}
						}
						else{
							if(c1<z){
								f[i][0][0][0]=(f[i][0][0][0]+solve(i+1,0,0,0,0,0,1))%mod;
								f[i][1][0][0]=(f[i][1][0][0]+solve(i+1,1,1,0,0,0,1))%mod;
							}
							else if(c1==z){
								f[i][0][0][0]=(f[i][0][0][0]+solve(i+1,0,0,0,0,0,0))%mod;
								f[i][0][0][1]=(f[i][0][0][1]+solve(i+1,0,0,0,0,1,1))%mod;
								f[i][1][0][0]=(f[i][1][0][0]+solve(i+1,1,1,0,0,0,0))%mod;
								f[i][1][0][1]=(f[i][1][0][1]+solve(i+1,1,1,0,0,1,1))%mod;
							}
							else{
								f[i][0][0][0]=(f[i][0][0][0]+solve(i+1,0,0,0,0,0,0))%mod;
								f[i][1][0][0]=(f[i][1][0][0]+solve(i+1,1,1,0,0,0,0))%mod;
							}
						}
					}
					else{
						if(b1<y){
							if(c1<z) f[i][0][0][0]=(f[i][0][0][0]+solve(i+1,0,0,0,1,0,1))%mod;
							else if(c1==z){
								f[i][0][0][0]=(f[i][0][0][0]+solve(i+1,0,0,0,1,0,0))%mod;
								f[i][0][0][1]=(f[i][0][0][1]+solve(i+1,0,0,0,1,1,1))%mod;
							}
							else f[i][0][0][0]=(f[i][0][0][0]+solve(i+1,0,0,0,1,0,0))%mod;
						}
						else if(b1==y){
							if(c1<z){
								f[i][0][0][0]=(f[i][0][0][0]+solve(i+1,0,0,0,0,0,1))%mod;
								f[i][0][1][0]=(f[i][0][1][0]+solve(i+1,0,0,1,1,0,1))%mod;
							}
							else if(c1==z){
								f[i][0][0][0]=(f[i][0][0][0]+solve(i+1,0,0,0,0,0,0))%mod;
								f[i][0][1][0]=(f[i][0][1][0]+solve(i+1,0,0,1,1,0,0))%mod;
								f[i][0][0][1]=(f[i][0][0][1]+solve(i+1,0,0,0,0,1,1))%mod;
								f[i][0][1][1]=(f[i][0][1][1]+solve(i+1,0,0,1,1,1,1))%mod;
							}
							else{
								f[i][0][0][0]=(f[i][0][0][0]+solve(i+1,0,0,0,0,0,0))%mod;
								f[i][0][1][0]=(f[i][0][1][0]+solve(i+1,0,0,1,1,0,0))%mod;
							}
						}
						else{
							if(c1<z) f[i][0][0][0]=(f[i][0][0][0]+solve(i+1,0,0,0,0,0,1))%mod;
							else if(c1==z){
								f[i][0][0][0]=(f[i][0][0][0]+solve(i+1,0,0,0,0,0,0))%mod;
								f[i][0][0][1]=(f[i][0][0][1]+solve(i+1,0,0,0,0,1,1))%mod;
							}
							else f[i][0][0][0]=(f[i][0][0][0]+solve(i+1,0,0,0,0,0,0))%mod;
						}
					}
				}
	}
	return solve(0,0,1,0,1,0,1);
}
 
int qpow(int x,int y){
	int res=1;
	for(;y;y>>=1,x=1ll*x*x%mod)
		if(y&1) res=1ll*res*x%mod;
	return res;
}
 
int main(){
	scanf("%d%d%d%d%d%d",&l1,&r1,&l2,&r2,&l3,&r3);
	ans=((work(r1,r2,r3)-work(l1-1,r2,r3)-work(r1,l2-1,r3)-work(r1,r2,l3-1)+work(l1-1,l2-1,r3)+work(l1-1,r2,l3-1)+work(r1,l2-1,l3-1)-work(l1-1,l2-1,l3-1))%mod+mod)%mod;
	int az=1ll*(r1-l1+1)*(r2-l2+1)%mod*(r3-l3+1)%mod;
	printf("%d",1ll*(az-ans+mod)%mod*qpow(az,mod-2)%mod);
	return 0;
}

看这幽默的代码不去做大模拟真的可惜了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值