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 n21AiBi,求 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=n1i=1nAiBi=n1AiBi
关键就是保留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');
    }
}