题目链接
题目描述:

题解:dalao的写法都是找规律哒,作为萌新的我,只能暴力,先上一个暴力的代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
int a[maxn];
const int mod = 1e9 + 7;
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    long long ans=0;
    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++){
                      ans+=(a[i]*a[j])%mod;
                      ans%=mod;                
              }
            }
        }
    }
    cout<<ans;
}

很容易的能根据题意模拟出题意,但是。。交上去会T啊,那。只能优化它一手了
观察最内层循环

               for(int j=i;j<=r;j++){
                 ans+=(a[i]*a[j])%mod;
                 ans%=mod;                
              }

这个部分可以写作a[i]*(a[i]+a[i+1]+a[i+2]+...a[r])
那就很容易想到用前缀和来写后面的这一大块(a[i]+a[i+1]+a[i+2]+...a[r])
然后(开心的)用前缀和去优化这一层循环(这里用数组b表示数组a的前缀和

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
int a[maxn],b[maxn];
const int mod = 1e9 + 7;
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        b[i]=b[i-1]+a[i];
        b[i]%=mod;
    }
    long long ans=0;
    for(int l=1;l<=n;l++){
        for(int r=l;r<=n;r++){
            for(int i=l;i<=r;i++){
             ans+=a[i]*(b[r]-b[i-1]);
             ans%=mod;
            }
        }
    }
    cout<<ans;
}

发现还是会T,那只好继续优化辣
继续观察内层循环:

  for(int i=l;i<=r;i++){
      ans+=a[i]*(b[r]-b[i-1]);
      ans%=mod;
   }

这个东西可以写作a[i] * b[r] -a[i] * b[i-1]
即:(a[l]+a[l+1]+a[l+2]+...+a[r])* b[r] -(a[l] * b[l-1] + a[l+1] * b[l]+...+a[r] * b[r-1])
令 d[i]=a[i] * b[i-1]
原式=(b[r]-a[l-1]) * b[r] -(d[l]+d[l+1]...+d[r])
再对数组d进行计算前缀和:即c[i]=c[i-1]+a[i]*b[i-1]
原式=(b[r]-a[l-1]) *b[r] -(c[r]-c[l-1]);

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
int a[maxn],b[maxn],c[maxn];
const int mod = 1e9 + 7;
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        b[i]=b[i-1]+a[i];
        b[i]%=mod;
        c[i]=c[i-1]+a[i]*b[i-1];
    }
    long long ans=0;
    for(int l=1;l<=n;l++){
        for(int r=l;r<=n;r++){
            ans+=(b[r]-b[l-1])*(b[r])-(c[r]-c[l-1]);
            ans%=mod;
        }
    }
    cout<<ans;
}

发现还是会T
继续观察循环内部
拆开写为:b[r] * b[r] -b[l-1] * b[r] -c[r] +c[l-1]
对其求和为:(b[l] * b[l]+b[l+1] * b[l+1]+...+b[n] * b[n] )
-b[l-1] * (b[l]+b[l+1]+..+b[n]))
-(c[l]+c[l+1]+...+c[n])
+(n-l+1) * c[l-1]
发现有三个前缀和需要计算
令e[i]=e[i-1]+b[i]*b[i]
f[i]=f[i-1]+b[i]
g[i]=g[i-1]+c[i]
即循环可以写作:e[n]-e[l-1]-(b[l-1] * (f[n]-f[l-1]))-(g[n]-g[l-1])+(n-l+1) * c[l-1]
namo:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
int a[maxn],b[maxn],c[maxn],e[maxn],f[maxn],g[maxn];
const int mod = 1e9 + 7;
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        b[i]=b[i-1]+a[i];
        c[i]=c[i-1]+a[i]*b[i-1];
        e[i]=e[i-1]+b[i]*b[i];
        f[i]=f[i-1]+b[i];
        g[i]=g[i-1]+c[i];
        b[i]%=mod,c[i]%=mod,e[i]%=mod,f[i]%=mod,f[i]%=mod,g[i]%=mod;
    }
    long long ans=0;
    for(int l=1;l<=n;l++){
            ans+=e[n]-e[l-1]-(b[l-1] * (f[n]-f[l-1]))-(g[n]-g[l-1])+(n-l+1) * c[l-1];
            ans%=mod;
    }
    cout<<ans;
}

这样子就不会t了,
然后考虑int相乘可能会爆精度,全改成longlong (再加上各种取模操作

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
long long a[maxn],b[maxn],c[maxn],e[maxn],f[maxn],g[maxn];
const int mod = 1e9 + 7;
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        b[i]=b[i-1]+a[i];
        c[i]=c[i-1]+a[i]*b[i-1];
        e[i]=e[i-1]+b[i]*b[i];
        f[i]=f[i-1]+b[i];
        g[i]=g[i-1]+c[i];
        b[i]%=mod,c[i]%=mod,e[i]%=mod,f[i]%=mod,f[i]%=mod,g[i]%=mod;
    }
    long long ans=0;
    for(int l=1;l<=n;l++){
            ans+=e[n]-e[l-1]-(b[l-1] * (f[n]-f[l-1]))%mod+mod-(g[n]-g[l-1]+mod)+(n-l+1) * c[l-1];
            ans=(ans+mod)%mod;
    }
    cout<<ans;
}

然后就能过辣