[JXOI2018] 游戏

一道概率与期望(统计与组合)的题目,一位组合蒟蒻来见识一下自己有多弱。

明显的,我们可以把一些必须选完这些数才可以完成任务的数,这里成为假素数

可以埃筛筛出假素数的数量 k 可以枚举最后一个被选中的假素数的位置 \(i\) 其他的 \(k-1\) 可以在 \(i-1\) 个数中选择一个方案为 \(A_{k-1}^{i-1}\) 而其他的数随便放,方案为 \((n-k)!\), 所以贡献为 \(i \times A_{k-1}^{i-1} \times (n-k)!\) ,注意这里的组合数需要用逆元前缀来算,不然超时。

当然有一种更加简单的方法,直接算 \(t(p)\) 的期望,再乘上 \(n!\) 即可。这个期望也很简单,我们知道期望是线性的,这样的话就可直接把每一个决策的期望求和即可,这里的决策就是我们放的非假素数,我们已知每一个假素数的位置,就是每一个黑球,而我们的每一个白球就是每一个非假素数,可以插入的空间就是每一个假素数的中间和两边,共 \(k+1\) 个空格,而其中有 \(k/(k+1)\) 的概率会对总的期望有所贡献,所以期望就是 \(k+(n-k)*k/(k+1)\) ,即 \((n+1)/(k+1)\) ,所以总答案就是 \(n!*(n+1)/(k+1)=(n+1)!/(k+1)\)

first .method code

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9+7;
int ans=1,l,r,k,n,vis[10000005];
int pre[10000005];
int mul[10000005],imul[10000005],inv[10000005];
int qpow(int x,int y){
	int res=1;
	while(y){
		if(y&1)res*=x,res%=mod;
		x*=x,x%=mod;
		y>>=1;
	}
	return res;
}
signed main(){
	scanf("%lld%lld",&l,&r);
	n=r-l+1;
	for(int i=l;i<=r;i++){
		if(vis[i])continue;
		k++;
		for(int j=i;j<=r;j+=i)vis[j]=1;
	} 
	ans=0;
	pre[0]=1;
	for(int i=1;i<=n;i++)
		pre[i]=pre[i-1]*i,pre[i]%=mod;
	imul[n]=qpow(pre[n],mod-2);
	for(int i=n-1;~i;i--)imul[i]=imul[i+1]*(i+1)%mod;
	for(int i=k;i<=n;i++){
		ans+=pre[i-1]*imul[k-1]%mod*imul[i-k]%mod*pre[k]%mod*pre[n-k]%mod*i%mod;
		//cout<<ans<<endl;
		ans%=mod;
	}
	cout<<ans;
	return 0;
}

second.method code

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9+7;
int ans;
int l,r;
int a[10];
bool vis[10000005];
int k,n;
signed main(){
	scanf("%lld%lld",&l,&r);
	if(l==1){
		ans=1;
		int p=(1+r)*r/2;p%=mod;
		for(int i=1;i<=r-1;i++)
			ans *= i,ans%=mod;
		cout<<ans*p%mod<<endl;
		return 0;
	}
	n=r-l+1;
	for(int i=l;i<=r;i++){
		if(vis[i])continue;
		k++;
		for(int j=i;j<=r;j+=i)vis[j]=1;
	} 
	ans=1;
	for(int i=1;i<=n+1;i++){
		if(i==k+1)continue;
		ans*=i,ans%=mod; 
	}
	ans*=k;
	ans%=mod;
	cout<<ans;
	// k/(k+1) * (n+1)!
	return 0;
}
posted @ 2025-03-11 21:50  hnczy  阅读(13)  评论(0)    收藏  举报