异或之和

今天做了一道题,乍一看太难了,可仔细想一想就会发现这道题非常水(但思路还是很难想的,我是看到这道题有前缀和的标签才想到的)。

先看题目吧:

洛谷P3909 异或之积

 

如果打暴力,复杂度为O(n^3),最坏情况下是10^18,一定超时,那么就需要推一个便捷的式子,这里就需要开头说的前缀和。

下面讲思路:首先我们将式子分开,a3*a2*a1,a4*a3*a2,a4*a2*a1,a4*a3*a1,……,先看前面的部分,第二项和第一项a2*a1,a3*a2,a3*a1推出第二项是a2时第一项有a1,即a2*a1,第二项是a3时第一项有a2和a1,即a3*(a2+a1),这是得到一个新的序列q:q1是a1*(a0的前缀和)(q1=0),q2是a2*(a1的前缀和),……,qk就是ak*(a(k-1)的前缀和)。接着看第三项,第三项是a3时有a3*a2*a1=a3*q2=a3*(q2的前缀和),第三项是a4时有a4*a3*a2,a4*a3*a1,a4*a2*a1得到a4*(a3*a2+a3*a1+a2*a1)=a4*(a3*(a2+a1)+a2*a1)=a4*(q3+q2)=a4*(q3的前缀和),可以推出第三项是ak时得到ak*(q(k-1)的前缀和),再将它们加起来*6就可以了。

下面是代码:

#include<iostream>
#define mod 1000000007
using namespace std;
int n;
long long a[1000010];
long long q1[1000010];
long long q2[1000010];
long long ans;
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        q1[i]=(q1[i-1]+a[i])%mod;
        q2[i]=(q2[i-1]+q1[i-1]*a[i])%mod;
        ans+=a[i]*q2[i-1];
        ans%=mod;
    }
    cout<<(ans*6)%mod;
    return 0;
}

 

posted @ 2022-03-05 10:32  zzzzzz2  阅读(82)  评论(0)    收藏  举报