题目大意
求所有区间and值与or值乘积的和
瞎搞
枚举左端点,我们需要知道and值与or值均相同的区间可以直接做出来。
这样划分最多60个区间,用链表顺序保存可能使得and值和or值改变的右端点即可。
#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=1000000007;
int a[maxn],b[maxn][33],c[33],d[33],pre[maxn],next[maxn],cnt[maxn];
int i,j,k,l,r,t,n,m,ans,fi;
int main(){
scanf("%d",&n);
fo(i,1,n){
scanf("%d",&a[i]);
k=a[i];
fo(j,0,31){
b[i][j]=k%2;
k/=2;
}
}
fi=n+1;
fd(i,n,1){
l=a[i];r=a[i];
j=fi;k=i;
while (k<=n){
(ans+=(ll)l*r%mo*(j-k)%mo)%=mo;
l&=a[j];r|=a[j];
k=j;
j=next[j];
}
fo(j,0,31){
if (b[i][j]==0){
cnt[c[j]]--;
if (!cnt[c[j]]){
next[pre[c[j]]]=next[c[j]];
pre[next[c[j]]]=pre[c[j]];
if (fi==c[j]) fi=next[c[j]];
}
c[j]=i;
}
else{
cnt[d[j]]--;
if (!cnt[d[j]]){
next[pre[d[j]]]=next[d[j]];
pre[next[d[j]]]=pre[d[j]];
if (fi==d[j]) fi=next[d[j]];
}
d[j]=i;
}
}
cnt[i]+=32;
next[i]=fi;
pre[fi]=i;
fi=i;
}
printf("%d\n",ans);
}