异或之和
今天做了一道题,乍一看太难了,可仔细想一想就会发现这道题非常水(但思路还是很难想的,我是看到这道题有前缀和的标签才想到的)。
先看题目吧:
洛谷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; }