按位统计,考虑每个数作为最大值的贡献,只需统计其左右有奇数个1和偶数个1的区间个数即可。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define N 100010 #define P 1000000061 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int T,n,a[N],pre[N],suf[N],cntpre[N],cntsuf[N]; int main() { #ifndef ONLINE_JUDGE freopen("bzoj4750.in","r",stdin); freopen("bzoj4750.out","w",stdout); const char LL[]="%I64d "; #else const char LL[]="%lld "; #endif T=read(); while (T--) { n=read(); for (int i=1;i<=n;i++) a[i]=read(); pre[0]=0;a[0]=a[n+1]=P; for (int i=1;i<=n;i++) { int j=i-1; while (a[j]<a[i]) j=pre[j]; pre[i]=j; } suf[n+1]=n+1; for (int i=n;i>=1;i--) { int j=i+1; while (a[j]<=a[i]) j=suf[j]; suf[i]=j; } int ans=0; for (int j=0;j<30;j++) { for (int i=0;i<=n+1;i++) cntpre[i]=cntsuf[i]=0; int s=0; for (int i=1;i<=n;i++) { s^=a[i]&(1<<j); cntpre[i]=cntpre[i-1]+(s>0); } s=0; for (int i=n;i>=1;i--) { s^=a[i]&(1<<j); cntsuf[i]=cntsuf[i+1]+(s>0); } int t=0; for (int i=1;i<=n;i++) { t^=a[i]&(1<<j),s^=a[i]&(1<<j); int x=t?cntsuf[pre[i]+1]-cntsuf[i+1]:i-pre[i]-(cntsuf[pre[i]+1]-cntsuf[i+1]); int y=s?cntpre[suf[i]-1]-cntpre[i-1]:suf[i]-i-(cntpre[suf[i]-1]-cntpre[i-1]); ans=(ans+1ll*a[i]*(1<<j)%P*(1ll*x*(suf[i]-i-y)%P+1ll*y*(i-pre[i]-x)%P))%P; } } printf("%d ",ans); } return 0; }