1. 程式人生 > 實用技巧 >2020杭電HDU-6827多校第六場Road To The 3rd Building(找規律求期望)

2020杭電HDU-6827多校第六場Road To The 3rd Building(找規律求期望)

題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=6827
CSDN食用連結:https://blog.csdn.net/qq_43906000/article/details/107875712

Problem Description
Because of the thriller adventure game The 3rd Building, there are fewer and fewer students who would like to go to the 3rd Building. So few students are working in the studio in the 3rd Building. Students are even more reluctant to go to the 3rd Building for experiments, which are also annoying.

Kanade takes responsibility to improve this status. She thinks it a good idea to decorate the ginkgo trees along the road to the 3rd Building, making them cute. There are n ginkgo trees that are planted along the road, numbered with \(1…n\). Each tree has a cute value. The cute value of tree \(i\) is \(s_i\)

.

Kanade defines a plan as an ordered pair \((i,j)\), here \(1≤i≤j≤n\). It means a student will appear at the position of the tree \(i\) magically, walk along the road, and finally stop walking at the position of the tree \(j\). The cute level of a plan is the average of the cute value of the trees visited. Formally, the cute level of plan \((i,j)\)

is \(\frac{1}{j-i+1}\sum_{k=i}^js_k\)

Kanade wants to know the mathematical expectation of the cute level if a student will take a plan among all these plans in a uniformly random way. But she is busy with learning Computer Networking, would you help her?

Input
The first line of the input contains an integer T — the number of testcases. You should process these testcases independently.

The first line of each testcase contains an integer n — the number of ginkgo trees.

The second line of each testcase contains \(n\) integers \(s_i\) — the cute value of each ginkgo tree, space-separated.

\(1\leq T\leq 20,1\leq n\leq 2\times10^5,1\leq s_i\leq 10^9\)
It is guaranteed that \(\sum n\leq10^6\)

Output
For each testcase, output the answer in the fraction form modulo \(10^9+7\) in one line. That is, if the answer is \(frac{P}{Q}\), you should output \(P⋅Q^{−1}\ mod\ (10^9+7)\), where \(Q^{−1}\) denotes the multiplicative inverse of \(Q\) modulo \(10^9+7\).

Sample Input
3
3
1 3 2
6
1 1 4 5 1 4
9
7325 516 56940 120670 16272 15007 337527 333184 742294

Sample Output
83333336
188888893
303405448

Hint
The answer to the first testcase is 25/12.

題目大意:給你n個數,現在任意選擇一個區間求其平均值,你需要求出這個平均值的期望。

一個區間的平均值,也就是\(\frac{\sum a_i}{len}\),那麼每次我們都需要對\(len\)取逆元,如果列舉數的話,區間長度不一樣很難搞,所以我們考慮列舉區間長度,那麼事情就變得簡單了許多,我們只需要判斷該區間長度下每個數出現的次數,然後將其對應的值乘上去最後做個加法,就是該區間長度下能夠取得的值了,最後我們再除以一個區間長度就OK了。那麼怎麼判斷每個區間長度下的每個數的出現次數呢?其實也很好辦,我們直接手動繪製兩個表就好了:

對於: 1 1 4 5 1 4
len=1:\(\color{#FF3030}{1}\) 1 1 1 1 1
len=2:1 \(\color{#FF3030}{2}\) 2 2 2 1
len=3:1 2 \(\color{#FF3030}{3}\) 3 2 1
\(-------\)
len=4:1 2 3 3 2 1
len=5:1 2 2 2 2 1
len=6:1 1 1 1 1 1

是不是發現一個很有趣的現象?也就是說我們很容易計算出每個長度下的分子!!,我們可以用字首和\(sum\)先記錄一下,然後我們再做個\(ssum\),用來表示每個長度下的分子。那麼就很容易得到:\(ssum[i]=ssum[i-1]+sum[n-i+1]-sum[i-1]\)
那麼我們就很容易得出如下程式碼:

ssum[1]=sum[n];
for (int i=2; i<=n/2; i++)
	ssum[i]=(ssum[i-1]+sum[n-i+1]-sum[i-1]+mod)%mod;
ssum[n]=sum[n];
for (int i=n-1; i>=n/2+1; i--)
	ssum[i]=(ssum[i+1]+sum[i]-sum[n-i]+mod)%mod;

當然看著,上面的圖,我們很容易觀察到他是一個偶數,它雖然對稱,但它沒有中心,那麼我們很容易猜想奇數會出現一箇中心,那麼簡單畫一下就是:

1 1 1 1 1
1 2 2 2 1
1 2 3 2 1
1 2 2 2 1
1 1 1 1 1

那麼很容易發現就第\(\frac{n}{2}+1\)行比較特殊,我們單獨拎出來計算就是了。

以下是AC程式碼:

#include <bits/stdc++.h>
using namespace std;

#define debug printf("@#$@#$\n")
typedef long long ll;
const int mac=2e5+10;
const int mod=1e9+7;

ll qpow(ll a,ll b)
{
    ll ans=1; 
    a%=mod;
    while (b){
        if (b&1) ans=ans*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ans;
}

ll sum[mac],ssum[mac];
int a[mac];

int main(int argc, char const *argv[])
{
    int t,n;
    scanf ("%d",&t);
    while (t--){
        scanf ("%d",&n);
        for (int i=1; i<=n; i++){
            scanf ("%d",&a[i]);
            sum[i]=(sum[i-1]+a[i])%mod;
        }
        if (n&1){
            ssum[1]=sum[n];
            for (int i=2; i<=n/2; i++)
                ssum[i]=(ssum[i-1]+sum[n-i+1]-sum[i-1]+mod)%mod;
            ssum[n/2+1]=(ssum[n/2]+a[n/2+1])%mod;
            ssum[n]=sum[n];
            for (int i=n-1; i>=n/2+2; i--)
                ssum[i]=(ssum[i+1]+sum[i]-sum[n-i]+mod)%mod;
        }
        else {
            ssum[1]=sum[n];
            for (int i=2; i<=n/2; i++)
                ssum[i]=(ssum[i-1]+sum[n-i+1]-sum[i-1]+mod)%mod;
            ssum[n]=sum[n];
            for (int i=n-1; i>=n/2+1; i--)
                ssum[i]=(ssum[i+1]+sum[i]-sum[n-i]+mod)%mod;
        }
        ll ans=0;
        for (int i=1; i<=n; i++){
            ans=(ans+ssum[i]*qpow(i,mod-2)%mod)%mod;
        }
        ans=((ans*2%mod) * qpow(1LL*n*(n+1),mod-2)%mod);
        printf("%lld\n",ans);
    }
    return 0;
}