【2020年杭电暑假第六场】6827 Road To The 3rd Building

【2020年杭电暑假第六场】6827 Road To The 3rd Building 数学推导

    • 题意
    • 思路
    • Code

传送门: http://acm.hdu.edu.cn/showproblem.php?pid=6827

题意

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 si.

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 1j−i+1∑jk=isk.

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 si — the cute value of each ginkgo tree, space-separated.

1≤T≤20,1≤n≤2×105,1≤si≤109

It is guaranteed that ∑n≤106.

Output
For each testcase, output the answer in the fraction form modulo 109+7 in one line. That is, if the answer is PQ, you should output P⋅Q−1mod(109+7), where Q−1 denotes the multiplicative inverse of Q modulo 109+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

有n棵银杏树,每棵树都有可爱价值,当从第i棵树走到第j棵树,则他们的平均可爱价值为 ∑ k = i j s [ k ] j − i + 1 \frac{\sum_{k=i}^{j}s[k]}{j-i+1} ji+1k=ijs[k],最后求这些可爱价值的数学期望。

思路

我的思路是手动模拟一下每种情况。
【2020年杭电暑假第六场】6827 Road To The 3rd Building_第1张图片
先从起点为 1 1 1开始,首先是 1 1 1 1 1 1,那就是这一点的平均可爱价值为 s [ 1 ] 1 \frac{s[1]}{1} 1s[1],然后 1 1 1走到 2 2 2的平均可爱价值为 s [ 1 ] + s [ 2 ] 2 \frac{s[1]+s[2]}{2} 2s[1]+s[2],然后 1 1 1走到 3 3 3的平均可爱价值为 s [ 1 ] + s [ 2 ] + s [ 3 ] 3 \frac{s[1]+s[2]+s[3]}{3} 3s[1]+s[2]+s[3]…最后就是 1 1 1走到 n n n的平均可爱价值为 s [ 1 ] + s [ 2 ] + . . . s [ n ] n \frac{s[1]+s[2]+...s[n]}{n} ns[1]+s[2]+...s[n]
然后从起点为 2 2 2开始,首先是 2 2 2 2 2 2,那就是这一点的平均可爱价值为 s [ 2 ] 1 \frac{s[2]}{1} 1s[2],最后就是 2 2 2走到 n n n的平均可爱价值为 s [ 2 ] + . . . s [ n ] n − 1 \frac{s[2]+...s[n]}{n-1} n1s[2]+...s[n]
中间省略很多起点。。。。。
接着就是从起点为 n − 1 n-1 n1开始,那这只有两种情况,分别为 s [ n − 1 ] 1 \frac{s[n-1]}{1} 1s[n1] s [ n − 1 ] + s [ n ] 2 \frac{s[n-1]+s[n]}{2} 2s[n1]+s[n]
最后就是从起点为 n n n开始,就是 n n n n n n,平均可爱价值为 s [ n ] 1 \frac{s[n]}{1} 1s[n]

我们这里只是从一个起点到另外一个终点的平均可爱价值求出来,题目说可以 i i i j j j j j j i i i两种走法,但是这两种的结果都是一样的平均可爱价值,只需要求一次就可。

那我们把这些情况重新排列一下,如下所示:

i = 1 : s [ 1 ] 1 + s [ 1 ] + s [ 2 ] 2 + s [ 1 ] + s [ 2 ] + s [ 3 ] 3 . . . . . . + s [ 1 ] + s [ 2 ] + . . . s [ n ] n i=1:\frac{s[1]}{1}+\frac{s[1]+s[2]}{2}+\frac{s[1]+s[2]+s[3]}{3}......+\frac{s[1]+s[2]+...s[n]}{n} i=11s[1]+2s[1]+s[2]+3s[1]+s[2]+s[3]......+ns[1]+s[2]+...s[n]

i = 2 : s [ 2 ] 1 + s [ 2 ] + s [ 3 ] 2 + s [ 2 ] + s [ 3 ] + s [ 4 ] 3 . . . . . . + s [ 2 ] + . . . s [ n ] n − 1 i=2:\frac{s[2]}{1}+\frac{s[2]+s[3]}{2}+\frac{s[2]+s[3]+s[4]}{3}......+\frac{s[2]+...s[n]}{n-1} i=2:1s[2]+2s[2]+s[3]+3s[2]+s[3]+s[4]......+n1s[2]+...s[n]

. . . ... ...
i = n − 1 : s [ n − 1 ] 1 + s [ n − 1 ] + s [ n ] 2 i=n-1:\frac{s[n-1]}{1}+\frac{s[n-1]+s[n]}{2} i=n1:1s[n1]+2s[n1]+s[n]

i = n : s [ n ] 1 i=n:\frac{s[n]}{1} i=n:1s[n]

观察上述所有情况,我们把分母相同的分式相加得(设分母为 k k k):

k = 1 : s [ 1 ] + s [ 2 ] + . . . + s [ n ] 1 k=1:\frac{s[1]+s[2]+...+s[n]}{1} k=1:1s[1]+s[2]+...+s[n]

k = 2 : s [ 1 ] + 2 ∗ ( s [ 2 ] + . . . + s [ n − 1 ] ) + s [ n ] 2 k=2:\frac{s[1]+2*(s[2]+...+s[n-1])+s[n]}{2} k=2:2s[1]+2(s[2]+...+s[n1])+s[n]

这里要好好品一下, s [ 2 ] 到 s [ n − 1 ] s[2]到s[n-1] s[2]s[n1]都是要乘 2 2 2的。那么下面的情况都是要乘上一些系数,而且都是呈三角形状态。
k = 3 : s [ 1 ] + 2 ∗ s [ 2 ] + 3 ∗ ( s [ 3 ] + . . . s [ n − 2 ] ) + 2 ∗ s [ n − 1 ] + s [ n − 1 ] 3 k=3:\frac{s[1]+2*s[2]+3*(s[3]+...s[n-2])+2*s[n-1]+s[n-1]}{3} k=3:3s[1]+2s[2]+3(s[3]+...s[n2])+2s[n1]+s[n1]

省 略 很 多 分 母 。 。 。 。 。 。 省略很多分母。。。。。。

k = n − 2 : s [ 1 ] + 2 ∗ s [ 2 ] + 3 ∗ ( s [ 3 ] + . . . s [ n − 2 ] ) + 2 ∗ s [ n − 1 ] + s [ n − 1 ] n − 2 k=n-2:\frac{s[1]+2*s[2]+3*(s[3]+...s[n-2])+2*s[n-1]+s[n-1]}{n-2} k=n2:n2s[1]+2s[2]+3(s[3]+...s[n2])+2s[n1]+s[n1]

k = n − 1 : s [ 1 ] + 2 ∗ ( s [ 2 ] + . . . + s [ n − 1 ] ) + s [ n ] n − 1 k=n-1:\frac{s[1]+2*(s[2]+...+s[n-1])+s[n]}{n-1} k=n1:n1s[1]+2(s[2]+...+s[n1])+s[n]

k = n : s [ 1 ] + s [ 2 ] + . . . + s [ n ] n k=n:\frac{s[1]+s[2]+...+s[n]}{n} k=n:ns[1]+s[2]+...+s[n]

这 里 有 个 规 律 , k = 1 和 k = n 的 分 子 相 同 , 得 出 k 和 n − k + 1 的 分 子 是 相 同 的 , 而 且 分 子 随 着 分 母 的 变 大 ( 1 − n 2 ) 呈 现 一 个 上 述 说 的 三 角 形 状 态 , 中 间 的 s [ i ] 的 系 数 都 是 逐 渐 递 增 , 笔 者 的 语 言 组 织 太 差 , 就 自 行 理 解 一 下 。 所 以 下 面 我 们 求 平 均 可 爱 价 值 就 可 以 O ( n 2 ) 求 。 这里有个规律,k=1和k=n的分子相同,得出k和n-k+1的分子是相同的,而且分子随着分母的变大(1 - \frac{n}{2})呈现一个上述说的三角形状态,中间的s[i]的系数都是逐渐递增,笔者的语言组织太差,就自行理解一下。所以下面我们求平均可爱价值就可以O(\frac{n}{2})求。 k=1k=n,knk+112ns[i]O(2n)

注意,当n为偶数的时候可以直接上面方法求,但是当n为奇数的时候,最中间的数 s [ n / 2 + 1 ] s[n/2+1] s[n/2+1]要另外加上,不要忘记!

分母我们可以预处理线性逆元,分子我们可以先预处理前缀和,然后根据(分母增大)系数加上相对应的前缀和。

Code

#include 

using namespace std;

typedef long long ll;
typedef long double ld;
typedef pair<int, int> pdd;

#define INF 0x7f7f7f
#define mem(a, b) memset(a , b , sizeof(a))
#define FOR(i, x, n) for(int i = x;i <= n; i++)

const ll mod = 1e9 + 7;
// const int maxn = 1e5 + 10;
// const double eps = 1e-6;

const int N = 2e5 + 10;

ll invn[N];

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

void Init() {
    invn[1] = 1;
    for(int i = 2;i < 200005; i++)
        invn[i] = mod - (mod / i) * invn[mod % i] % mod;
}

ll a[N];
ll f[N];

void solve() {
    int T;
    Init();
    scanf("%d",&T);
    f[0] = 0;
    while(T--) {
        ll n;
        ll ans = 0;
        scanf("%lld",&n);
        for(int i = 1;i <= n; i++) {
            scanf("%lld",&a[i]);
            f[i] = (f[i - 1] + a[i] % mod) % mod;
        }

        ll k = 0;

          for(int i = 1;i <= n / 2; i++) {
            k = (k + f[n - i + 1] - f[i - 1] + mod) % mod;
            ans = (ans + k * invn[i] % mod) % mod;
            ans = (ans + k * invn[n - i + 1] % mod) % mod;
        }

        if(n % 2 != 0) {
            ans = (ans + (k + a[n / 2 + 1]) % mod * invn[n / 2 + 1] % mod) % mod;
        }

        ans = (ans * quick_pow(((n + 1) * n / 2) % mod, mod - 2)) % mod;
        printf("%lld\n",ans % mod);
    }
}


signed main() {
    ios_base::sync_with_stdio(false);
    //cin.tie(nullptr);
    //cout.tie(nullptr);
#ifdef FZT_ACM_LOCAL
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
    signed test_index_for_debug = 1;
    char acm_local_for_debug = 0;
    do {
        if (acm_local_for_debug == '$') exit(0);
        if (test_index_for_debug > 20)
            throw runtime_error("Check the stdin!!!");
        auto start_clock_for_debug = clock();
        solve();
        auto end_clock_for_debug = clock();
        cout << "Test " << test_index_for_debug << " successful" << endl;
        cerr << "Test " << test_index_for_debug++ << " Run Time: "
             << double(end_clock_for_debug - start_clock_for_debug) / CLOCKS_PER_SEC << "s" << endl;
        cout << "--------------------------------------------------" << endl;
    } while (cin >> acm_local_for_debug && cin.putback(acm_local_for_debug));
#else
    solve();
#endif
    return 0;
}

由于线性逆元的板子我把括号的位置敲错地方,导致一直都是wa的状态,我是傻逼,我是傻逼,我是傻逼,重要的事情说三遍!!!

你可能感兴趣的:(题解)