题目大意
区间价值定义为最大值乘异或和。
求所有区间价值和。
随便搞搞
拆开来每一位单独搞,那每个位置是0或1,贡献需要有奇数个1。
首先枚举最大值,搞出它的掌控区间。
然后通过一些预处理简单得到一个区间前/后缀子区间有多少个有奇/偶数个1,就可以统计了。
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int maxn=100000+10,mo=1000000061,maxws=31;
int a[maxn],b[maxn],L[maxn],R[maxn],sum[maxn],num[maxn][2],cnt[maxn][2];
int i,j,k,l,t,n,m,ans,ca;
int read(){
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
int getl(int l,int r,int x){
if (l>r) return 0;
int t=((sum[r]-sum[l-1])%2+2)%2;
return cnt[l][x]-cnt[r+1][(x+t)%2];
}
int getr(int l,int r,int x){
if (l>r) return 0;
int t=((sum[r]-sum[l-1])%2+2)%2;
return num[r][x]-num[l-1][(x+t)%2];
}
int main(){
ca=read();
while (ca--){
n=read();
fo(i,1,n) a[i]=read();
fo(i,1,n){
j=i-1;
while (j&&a[j]<=a[i]) j=L[j]-1;
L[i]=j+1;
}
fd(i,n,1){
j=i+1;
while (j<=n&&a[j]<a[i]) j=R[j]+1;
R[i]=j-1;
}
ans=0;
fo(j,0,maxws){
fo(i,1,n)
if (((1<<j)&a[i])!=0) b[i]=1;else b[i]=0;
fo(i,1,n)
fo(k,0,1) num[i][k]=num[i-1][(k+b[i])%2]+(b[i]==k);
cnt[n+1][0]=cnt[n+1][1]=0;
fd(i,n,1)
fo(k,0,1) cnt[i][k]=cnt[i+1][(k+b[i])%2]+(b[i]==k);
fo(i,1,n) sum[i]=(sum[i-1]+b[i])%2;
fo(i,1,n){
ans=(ans+(ll)a[i]*getr(L[i],i,1)%mo*getl(i+1,R[i],0)%mo*(1<<j)%mo)%mo;
ans=(ans+(ll)a[i]*getr(L[i],i,0)%mo*getl(i+1,R[i],1)%mo*(1<<j)%mo)%mo;
ans=(ans+(ll)a[i]*getr(L[i],i,1)%mo*(1<<j)%mo);
}
}
(ans+=mo)%=mo;
printf("%d\n",ans);
}
}