标签:tps 假设 tin 最大值 最大 区间 register ++ enable
题目要求合法的区间个数,这里考虑用总区间个数减去不合法的个数
假设某个数为区间最大值,那么包含这个数的最长区间内,所有数小于他并且所有数没有这个最大值没有的二进制位,可以按位考虑每个数\(i\)在\(j\)这一位上向左和向右第一个二进制位为1的位置,分别记为\(l_{i,j},r_{i,j}\),然后每个数再考虑所有二进制为0的位上的\(l_{i,j},r_{i,j}\)区间的交集,左右端点为\(ll,rr\),那个这一位对答案加上\((i-ll)*(rr-j)\)
要注意,前面可能有值相同的数,导致这次计算的\(ll\)包含了上次计算过的区间,这时候要让\(ll\)和\(a_i\)上次出现的位置取max
// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define LL long long
#define il inline
#define re register
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define db double
#define eps (1e-8)
using namespace std;
const int N=200000+10;
il LL rd()
{
re LL x=0,w=1;re char ch=0;
while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*w;
}
int n,a[N],l[N][33],r[N][33];
LL ans;
map<int,int> la;
int main()
{
n=rd();
for(int i=1;i<=n;i++) a[i]=rd();
for(int i=1;i<=n;i++)
for(int j=0;j<=32;j++)
l[i][j]=(a[i]&(1<<j))?i:l[i-1][j];
for(int j=0;j<=32;j++) r[n+1][j]=n+1;
for(int i=n;i>=1;i--)
for(int j=0;j<=32;j++)
r[i][j]=(a[i]&(1<<j))?i:r[i+1][j];
for(LL i=1;i<=n;i++)
{
LL ll=0,rr=n+1;
for(int j=0;j<=32;j++)
{
if(a[i]&(1<<j)) continue;
ll=max(ll,l[i][j]),rr=min(rr,r[i][j]);
}
ll=max(ll,la[a[i]]);
la[a[i]]=i;
ans+=(i-ll)*(rr-i);
}
printf("%lld\n",1ll*n*(n+1)/2-ans);
return 0;
}
标签:tps 假设 tin 最大值 最大 区间 register ++ enable
原文地址:https://www.cnblogs.com/smyjr/p/9691022.html