scp t2
首先我们拆贡献,拆成所有区间的按位或和之和,加上所有区间的
前面这一部分是好计算的,拆位然后正难则反,每一位假设总共
我们看后面一部分什么时候会有贡献。暴力一下得出结论,只有当
我们枚举
- 区间内包含
0\sim 2^k-1 的所有数。 - 区间内不包含有
2^k 这一二进制位的数。
我们枚举左端点,计算满足第一个条件的最左端的右端点,和不满足第二个条件的最左端的右端点,两者相减就是这个左端点对应的合法区间数(当然可能不存在合法区间,需要判一下)。这就是 AT_pakencamp_2023_day3_f,可以用双指针实现。枚举到每个
总时间复杂度
#include<bits/stdc++.h>
using namespace std;
unsigned long long ans=0;
int a[2000005];
int c[2000005];
int lp[2000005],rp[2000005];
int main(){
ios::sync_with_stdio(0);cin.tie(0);
int n;
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
ans=1073741823ull*(1ull*n*(n+1)/2);
int cnt=0;
for(int i=0;i<=29;i++){
cnt=0;
for(int j=1;j<=n;j++){
if(a[j]&(1<<i))cnt=0;
else cnt++;
ans-=cnt*(1ull<<i);
}
}
for(int i=0;i<=20;i++){
int p=1;
for(int j=0;j<(1<<i);j++)c[j]=0;
int tot=0,cnt=0;
for(int j=1;j<=n;j++){
if(j>1&&a[j-1]<(1<<i)){
c[a[j-1]]--;
if(!c[a[j-1]])cnt--;
}
while(p<=n&&cnt<(1<<i)){
if(a[p]<(1<<i)&&!c[a[p]])cnt++;
if(a[p]<(1<<i))c[a[p]]++;
p++;
}
if(cnt<(1<<i))lp[j]=n+1;
else lp[j]=p-1;
}
int ci=0;
p=1;
for(int j=1;j<=n;j++){
if(j>1&&(a[j-1]&(1<<i)))ci--;
while(p<=n&&!ci){
if(a[p]&(1<<i))ci++;
p++;
}
if(ci)rp[j]=p-1;
else rp[j]=n+1;
}
for(int j=1;j<=n;j++)ans+=max(rp[j]-lp[j],0)*(1ull<<i);
}
cout<<ans;
}
/*
祝世界上最可爱的灰之魔女伊蕾娜小姐生日快乐!
*/