Description
有些人在社交网络中使用过许多的密码,我们通过将各种形式的信息转化为 01 信号,再转化为整数,可以将这个人在一段时间内使用过的密码视为一个长度为 n 的非负整数序列 A_1,A_2,…,A_n 。一个人相邻几次在社交网络
中使用的密码很有可能是类似的,这使得密码并不是足够安全。为了检验某些人在某些时间段内是否可能受到不安全的影响,我们需要计算上述序列的复杂程度的值,这将作为我们评估密码复杂程度的一个部分。由于答案可能很大,你只需要给出答案对10^9+61 取模的值即可。
求
a
n
s
=
∑
i
=
1
n
∑
j
=
i
n
f
(
i
,
j
)
∗
g
(
i
,
j
)
ans=\sum_{i=1}^n\sum_{j=i}^n f(i,j)*g(i,j)
ans=i=1∑nj=i∑nf(i,j)∗g(i,j)
其中f(i,j)是i到j的异或和,g(i,j)是i到j的最大值
100% 的数据满足:1≤T≤200,1≤n≤10^ 5,1≤∑n≤10^ 6,0≤A_i≤10^9
Solution
套路题。。
考虑用单调栈求出最大值边界L和R。我们发现异或不好一起算,于是拆成30位分别算贡献
显然我们要算的就是跨过i的异或前缀和不等的数量,这个用桶乘一下就可以了
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define drp(i,st,ed) for (register int i=st;i>=ed;--i)
typedef long long LL;
const int MOD=1000000061;
const int N=100005;
int a[N],stack[N],L[N],R[N],sum[N];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
int main(void) {
for (int T=read();T--;) {
int n=read(),top=0,max=0; stack[0]=0;
rep(i,1,n) a[i]=read();
L[1]=1; stack[top=1]=1;
rep(i,2,n) {
for (;top&&a[i]>a[stack[top]];) top--;
L[i]=stack[top]+1;
stack[++top]=i;
} stack[0]=n+1; stack[top=1]=n; R[n]=n;
drp(i,n-1,1) {
for (;top&&a[i]>=a[stack[top]];) top--;
R[i]=stack[top]-1;
stack[++top]=i;
}
LL ans=0;
rep(p,0,30) {
LL wjp=1<<p,ls1,ls0,rs1,rs0,tmp;
rep(i,1,n) sum[i]=sum[i-1]^((a[i]&wjp)!=0);
rep(i,1,n) sum[i]+=sum[i-1];
rep(i,1,n) {
rs1=sum[R[i]]-sum[i-1];
ls1=sum[i-1]-sum[(L[i]==1)?0:(L[i]-2)];
rs0=R[i]-i+1-rs1;
ls0=i-L[i]+1-ls1;
tmp=(ls0*rs1+rs0*ls1)%MOD;
ans+=tmp*a[i]%MOD*wjp%MOD; (ans>=MOD)?(ans-=MOD):0;
}
}
printf("%lld\n", ans);
}
return 0;
}