【JZOJ 杂题选讲】北大集训2019 n门问题

题目

【JZOJ 杂题选讲】北大集训2019 n门问题_第1张图片

思路

首先我们考虑如何计算猜奖者所认为的概率
假设现在还有n扇门,第i扇有奖的概率是p[i]。
猜奖者选了第x扇门,主持人打开了第y扇门:
1.有p[x]的概率第x扇门就是有奖的,经过这次操作,p[x]显然不会变。
2.有1−p[x]的概率奖不在第x扇门,现在又多排除了第y扇门,
所以对z≠x且z≠y,p[z]∗=(1−p[x])/(1−p[x]−p[y]),意义为剩下的门均分这个这个多出来的概率。

每次选择的门,这次操作后,都会成为概率最小且独一无二的门。(无脑猜结论

现在问题变成有一个队列,一开始队列头一个位置上有n个球。
每次从队列头随机一个球x,然后从剩下的且不是答案的球去掉一个,把球x单独加到队尾。
这个一个O(n3)dp即可

然后,最难想到的是,n>10,答案为0,因为主持人可以控制奇偶

代码

#include
#define ll long long
using namespace std;
ll n;
ll a[100005];
ll b[100005];
ll pow_add(ll x,ll y,ll mod)
{
	ll ans=0;
	while(y)
	{
		if(y%2)
		{
			ans+=x;
			ans%=mod;
		}
		y/=2;
		x+=x;
		x%=mod;
	}
	return ans;
}
ll gcd(ll x,ll y)
{
	if(y==0)
	{
		return x;
	}
	return gcd(y,x%y);
}
void ex_gcd(ll a,ll b,ll &x,ll &y)
{
	if(b==0)
	{
		x=1;
		y=0;
		return;
	}
	ex_gcd(b,a%b,x,y);
	ll t=x;
	x=y;
	y=t-(a/b)*x;
}
ll ex_crt(ll n)
{
	ll M0=a[1];
	ll ans=b[1];
	for(int i=2;i<=n;i++)
	{
		ll r=gcd(M0,a[i]);
		ll bb=((b[i]-ans)%a[i]+a[i])%a[i];
		if(bb%r)
		{
			return -1;
		}
		bb/=r;
		ll M=M0/r;
		ll aa=a[i]/r;
		ll x,y;
		ex_gcd(M,aa,x,y);
		x=pow_add(x,bb,aa);
		ans+=x*M0;
		M0*=aa;
		ans=(ans%M0+M0)%M0;
	}
	return (ans%M0+M0)%M0;
}
int main()
{
	long long nn;
	scanf("%lld",&nn);
	for(int i=1;i<=nn;i++)
	{
		scanf("%lld%lld",&b[i],&a[i]);
	}
	cout<<fixed<<setprecision(6);
	n=ex_crt(nn);
	if(n<2) cout<<"error"<<endl;   
	if(n==2) cout<<1.0/2<<endl;
	if(n==3) cout<<2.0/3<<endl;
	if(n==4) cout<<5.0/8<<endl;
	if(n==5) cout<<7.0/15<<endl;
	if(n>5&&n<=10) cout<<2.0*(n-1)/n/(n-2)<<endl;
	if(n>10) cout<<"0.000000"<<endl;
	return 0;
}

你可能感兴趣的:(【JZOJ 杂题选讲】北大集训2019 n门问题)