N 色球 数学

【题目描述】
山山是一个双色球高手,每次必中无疑。
终有一天,他开始嫌弃双色球的颜色太少了,于是发明了 N 色球。
规则如下:
一个袋子里装有 n 个大小、形状相同的球,但每个球标有唯一的数字
你要从这个袋子中摸出 n-1 个球,最后的奖金为这 n-1 个球所标数字的乘积除以 p 的余数。
山山想知道他得到奖金的期望。
【输入文件】
输入文件 nsq.in 的第 1 行包含 2 个正整数 n,p
第二行包含 n 个正整数 a1,a2...an,表示每个球所标的数字
【输出文件】
输出文件 nsq.out 仅包含一个实数,表示得到奖金的期望
答案的误差不能超过 1e-6
【样例输入】
3 100
2 1 7
【样例输出】
7.6666666667
【数据规模】
对于 20%的数据,n≤2000
对于 20%的数据,n≤10^5,ai≤10^5,p=1000000007
对于 60%的数据,n≤10^6,ai≤10^9,p≤1000000007


一开始看到这题大部分人可能会没思路,但是想一想一般都可以想到。

我们正难则反,考虑每次第i个求不选会怎样。

于是我们记录两个数组,分别保存前缀积和后缀积就ok啦。

不过要注意统计的时候要全部加上在除,不然会有精度问题。

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>

#define ll long long
#define il inline
#define db double

using namespace std;

il int gi()
{
	int x=0,y=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
		{
			if(ch=='-')
				y=-1;
			ch=getchar();
		}
	while(ch>='0'&&ch<='9')
		{
			x=x*10+ch-'0';
			ch=getchar();
		}
	return x*y;
}

int num[1000045];

ll front[1000045];

ll behind[1000045];

int main()
{
	freopen("nsq.in","r",stdin);
	freopen("nsq.out","w",stdout);

	int n,p;
	cin>>n>>p;

	for(int i=1;i<=n;i++)
		num[i]=gi();
	
	front[0]=1;
	for(int i=1;i<=n;i++)
		front[i]=(front[i-1]*num[i])%p;

	behind[n+1]=1;
	for(int i=n;i>=1;i--)
		behind[i]=(behind[i+1]*num[i])%p;

	db all=0;

	for(int i=1;i<=n;i++)
		all+=(db)((front[i-1]*behind[i+1])%p);
	
	printf("%.10f",all/(db)n);

	return 0;
}
原文地址:https://www.cnblogs.com/gshdyjz/p/7687151.html