1. 程式人生 > >2018年第四階段組隊訓練賽二十四場G區間權值

2018年第四階段組隊訓練賽二十四場G區間權值

問題 G: 區間權值

時間限制: 1 Sec  記憶體限制: 128 MB 提交: 82  解決: 39 [提交] [狀態] [討論版] [命題人:admin]

題目描述

小Bo有n個正整數a1..an,以及一個權值序列w1…wn,現在他定義 現在他想知道的值,需要你來幫幫他 你只需要輸出答案對109+7取模後的值

輸入

第一行一個正整數n 第二行n個正整數a1..an 第三行n個正整數w1..wn 1≤n≤3×105 1≤ai≤107 1≤wi≤107

輸出

輸出答案對109+7取模後的值

樣例輸入

3
1 1 1
1 1 1

樣例輸出

10

直接寫肯定是三層for,超時麼誒跑,

因為字首和很熟悉了,所以直接去掉一層,也就是\sum_{i=l}^{r}a[i] = sum[r]-sum[l-1]

但是還是兩層的for,O(N^2),這肯定也不行,

先寫個暴力看下,注意輸入的時候,將a[i] = a[i] + a[i-1],就將a陣列直接變成了字首和sum陣列

for(int i=1; i<=n; i++)
    for(int j=i; j<=n; j++)
        ans1 = (ans1 + (a[j]-a[i-1]+p)%p*w[j-i+1]%p)%p;

以我對這個的理解就把他等價成了下面這個,就是從暴力點變成了暴力區間長度

for(int i=1; i<=n; i++)
    for(int j=0; j<=n-i; j++)
        ans2 = (ans2 + w[i]*(a[j+i]-a[j]+p)%p)%p;

那麼明顯可以這樣

提出公因式w[i],然後將中間的求和即可

那麼注意觀察,中間的項

例如

w[2]*((a[2]-a[0])+(a[3]-a[1])+(a[4]-a[2])+(a[5]-a[3])******)

注意中間有些項抵消了,那麼我們需要的就只是前面和後面的某些項就可以了,

例如上面那個就是

w[2]*((a[5]+a[4])-(a[0]-a[1]))

顯然又需要字首和來求區間和,那麼用另一個數組存輸入的字首和的字首和就好了

程式碼A了,但是還有些小問題,就是本來應該對稱的,但是不知道為什麼在i小於n/2的時候有些字首和是不對的

所以我一律採用後半段計算的字首和,

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
const int maxn = 3e5+7,p = 1e9+7;
ll a[maxn],b[maxn],w[maxn];
int main()
{
    cin>>n;
    //while(cin>>n)
    {
        for(int i=1; i<=n; i++)
        {
            scanf("%lld",&a[i]);
            a[i] = (a[i] + a[i-1])%p;
            b[i] = (a[i] + b[i-1])%p;
        }
 
        for(int i=1; i<=n; i++)
            scanf("%lld",&w[i]);
        ll ans1 = 0, ans2 = 0,ans3 = 0;
        /*for(int i=1; i<=n; i++)
        {
            for(int j=i; j<=n; j++)
            {
                ans1 = (ans1 + (a[j]-a[i-1]+p)%p*w[j-i+1]%p)%p;
            }
        }
        for(int i=1; i<=n; i++)
        {
            ll t = 0;
            for(int j=0; j<=n-i; j++)
            {
                ll c = w[i]*(a[j+i]-a[j]+p)%p;
                ans2 = (ans2 + c)%p;
                t = (t+c)%p;
                //if(i==3)
                    //printf("%d->%d----%lld\n",j,j+i,c);
            }
            printf("%d---%lld\n",i,t/w[i]);
        }*/
        for(int i=1; i<=n; i++)
        {
            int ti = i<=n/2?n-i+1:i;
            ll t = ((b[n] - b[n/ti*ti-1]+p)%p - b[n%ti] +p )%p*w[i]%p;
            //printf("%d--%lld\n",i,t/w[i]);
            ans3 = (ans3 + t)%p;
        }
        printf("%lld\n",ans3);
    }
    return 0;
}
/*
7
1 2 3 4 5 6 7
1 2 3 4 5 6 7
1->3----18
2->4----27
3->5----36
4->6----45
5->7----54
1--28
2--96
3--144
4--256
5--300
6--288
7--196
1344 1344 1308
 
*/
/*
8
1 2 3 4 5 6 7 8
1 2 3 4 5 6 7 8
1---36
2---126
3---243
4---360
5---450
6---486
7---441
8---288
1--36
2--72
3--243
4--144
5--450
6--486
7--441
8--288
2430 2430 2160
 
*/