[ACM]【prefix/求和/取餘】牛客練習賽64 序列卷積之和

序列卷積之和

傳送門
題意:求l=1nr=lni=lrj=irai×ajmod  1e9+7\sum_{l=1}^n\sum_{r=l}^n\sum_{i=l}^r\sum_{j=i}^ra_i\times a_j\mod 1e9+7
題目

思路:

本弱雞隻會找規律(。看到題解恍然大悟。
就是強行用前綴和把循環一層一層剝掉。
一開始是

for(int l=1;l<=n;l++)
	for(int r=l;r<=n;r++)
		for(int i=l;i<=r;i++)
			for(int j=i;j<=r;j++)
				sum+=a[i]*a[j];

把最內層循環展開,是
a[i]a[i]+a[i]a[i+1]+...+a[i]a[r]a[i]*a[i]+a[i]*a[i+1]+...+a[i]*a[r]

a[i](a[i]+a[i+1]+...+a[r])a[i]*(a[i]+a[i+1]+...+a[r])
我們求a[i]a[i]的前綴和,設爲b[i]b[i]

a[i](b[r]b[i1])a[i]*(b[r]-b[i-1])

for(int l=1;l<=n;l++)
	for(int r=l;r<=n;r++)
		for(int i=l;i<=r;i++)
			sum+=a[i]*(b[r]-b[i-1]);

把最內層循環展開,是
a[l](b[r]b[l1])+a[l+1](b[r]b[l+11])+...+a[r](b[r]b[r1])a[l]*(b[r]-b[l-1])+a[l+1]*(b[r]-b[l+1-1])+...+a[r]*(b[r]-b[r-1])
拆開小括號,重新組合,得
b[r](a[l]+a[l+1]+...+a[r])(a[l]b[l1]+a[l+1]b[l+11]+...+a[r]a[r1])b[r]*(a[l]+a[l+1]+...+a[r])-(a[l]*b[l-1]+a[l+1]*b[l+1-1]+...+a[r]*a[r-1])

b[r](b[r]b[l1])(a[l]b[l1]+a[l+1]b[l+11]+...+a[r]a[r1])b[r]*(b[r]-b[l-1])-(a[l]*b[l-1]+a[l+1]*b[l+1-1]+...+a[r]*a[r-1])
我們求a[i]b[i1]a[i]*b[i-1]的前綴和,設爲c[i]c[i]

b[r](b[r]b[l1])(c[r]c[l1])b[r]*(b[r]-b[l-1])-(c[r]-c[l-1])

for(int l=1;l<=n;l++)
	for(int r=l;r<=n;r++)
		sum+=b[r]*(b[r]-b[l-1])-(c[r]-c[l-1]);

把最內層循環展開,是
b[l](b[l]b[l1])(c[l]c[l1])+b[l+1](b[l+1]b[l1])(c[l+1]c[l1])+...+b[n](b[n]b[l1])(c[n]c[l1])b[l]*(b[l]-b[l-1])-(c[l]-c[l-1])+b[l+1]*(b[l+1]-b[l-1])-(c[l+1]-c[l-1])+...+b[n]*(b[n]-b[l-1])-(c[n]-c[l-1])
拆開小括號,重新組合,得
(b[l]2+b[l+1]2+...+b[n]2)b[l1](b[l]+b[l+1]+...+b[n])(c[l]+c[l+1]+...+c[n])+(nl+1)c[l1](b[l]^2+b[l+1]^2+...+b[n]^2)-b[l-1]*(b[l]+b[l+1]+...+b[n])-(c[l]+c[l+1]+...+c[n])+(n-l+1)*c[l-1]
我們求b[i]2b[i]^2的前綴和,設爲d[i]d[i]
b[i]b[i]的前綴和,設爲e[i]e[i]
c[i]c[i]的前綴和,設爲f[i]f[i]

(d[n]d[l1])b[l1](e[n]e[l1])(f[n]f[l1])+(nl+1)c[l1](d[n]-d[l-1])-b[l-1]*(e[n]-e[l-1])-(f[n]-f[l-1])+(n-l+1)*c[l-1]

for(int l=1;l<=n;l++)
	sum+=(d[n]-d[l-1])-b[l-1]*(e[n]-e[l-1])-(f[n]-f[l-1])+(n-l+1)*c[l-1];

現在複雜度就簡化爲O(n)O(n)了。
接下來我們要對求餘進行常規操作:
在求bcdef數組的時候,直接每求一個都取餘,這個沒所謂。
但是在sum裏面,存在減法和乘法,事態就變得不同尋常了。
遇到減法之後,我們可以在減法進行的地方加mod,也可以在減法進行的地方做了乘法之後加mod,是一樣的。
那麼代碼就寫出來了。

代碼:

#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
const int maxn=2e5+4;
typedef long long ll;
ll a[maxn],b[maxn],c[maxn],d[maxn],e[maxn],f[maxn];
int main(){
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		b[i]=(b[i-1]+a[i])%mod;
		c[i]=(c[i-1]+a[i]*b[i-1])%mod;
		d[i]=(d[i-1]+b[i]*b[i])%mod;
		e[i]=(e[i-1]+b[i])%mod;
		f[i]=(f[i-1]+c[i])%mod;
	}
	ll ans=0;
	for(int l=1;l<=n;l++){
		ans+=(d[n]-d[l-1]-b[l-1]*(e[n]-e[l-1]))%mod+mod-(f[n]-f[l-1]+mod)+(n-l+1)*c[l-1];
		ans=(ans+mod)%mod;
	}
	printf("%lld\n",ans);
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章