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; }
PEACE