https://ac.nowcoder.com/acm/contest/874/D
题意:给定长度为
n
n
n的数组
A
[
]
,
B
[
]
A[],B[]
A[],B[],将两个数组随机打乱,求
∑
i
=
1
n
A
i
B
i
\sum_{i=1}^nA_iB_i
∑i=1nAiBi的期望值。保留30位小数。
思路:每个位置出现
A
i
,
B
i
A_i,B_i
Ai,Bi的概率是
1
n
2
\frac{1}{n^2}
n21,期望是
1
n
2
∗
A
i
∗
B
i
\frac{1}{n^2}*A_i*B_i
n21∗Ai∗Bi,求
s
u
m
的
话
,
也
就
是
答
案
=
1
n
∑
i
=
1
n
A
i
B
i
=
1
n
∗
∑
A
i
∗
∑
B
i
sum的话,也就是答案=\frac1{n}\sum_{i=1}^nA_iB_i=\frac1{n}*\sum{A_i}*\sum{B_i}
sum的话,也就是答案=n1∑i=1nAiBi=n1∗∑Ai∗∑Bi
关键就是保留30位小数。double和long double精度只够15~20位,因此要模拟竖式除法来算,在纸上举个例子就明白了,注意保留每一位数字的也要
l
l
ll
ll,因为整数位可能很大,而小数位只是0 ~ 9。
//华工软院E
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int T,n;
ll s1,s2,s;
ll num[40];
int main()
{
// freopen("input.in","r",stdin);
cin>>T;
while(T--)
{
cin>>n;
int x;
s1=s2=0;
for(int i=1;i<=n;i++)scanf("%d",&x),s1+=x;
for(int i=1;i<=n;i++)scanf("%d",&x),s2+=x;
ll s=s1*s2;
num[0]=s/n;
for(int i=1;i<=31;i++)
{
s=s%n*10;
num[i]=s/n;
}
if(num[31]>=5)num[30]++;
int p=30;
while(p>0&&num[p]==10){num[p-1]++;num[p]=0;p--;}
printf("%lld.",num[0]);
for(int i=1;i<=30;i++)printf("%lld",num[i]);
putchar('\n');
}
}