CF 875DHigh Cry

Disclaimer: there are lots of untranslateable puns in the Russian version of the statement, so there is one more reason for you to learn Russian :)

Rick and Morty like to go to the ridge High Cry for crying loudly — there is an extraordinary echo. Recently they discovered an interesting acoustic characteristic of this ridge: if Rick and Morty begin crying simultaneously from different mountains, their cry would be heard between these mountains up to the height equal the bitwise OR of mountains they've climbed and all the mountains between them.

Bitwise OR is a binary operation which is determined the following way. Consider representation of numbers x and y in binary numeric system (probably with leading zeroes) x = xk... x1x0 and y = yk... y1y0. Then z = x | y is defined following way: z = zk... z1z0, where zi = 1, if xi = 1 or yi = 1, and zi = 0 otherwise. In the other words, digit of bitwise OR of two numbers equals zero if and only if digits at corresponding positions is both numbers equals zero. For example bitwise OR of numbers 10 = 10102 and 9 = 10012 equals 11 = 10112. In programming languages C/C++/Java/Python this operation is defined as «|», and in Pascal as «or».

Help Rick and Morty calculate the number of ways they can select two mountains in such a way that if they start crying from these mountains their cry will be heard above these mountains and all mountains between them. More formally you should find number of pairs l and r (1 ≤ l < r ≤ n) such that bitwise OR of heights of all mountains between l and r (inclusive) is larger than the height of any mountain at this interval.

Input

The first line contains integer n (1 ≤ n ≤ 200 000), the number of mountains in the ridge.

Second line contains n integers ai (0 ≤ ai ≤ 109), the heights of mountains in order they are located in the ridge.

Output

Print the only integer, the number of ways to choose two different mountains.

题解:

求区间最大值<区间或的区间个数。

n个元素就有 \frac{n*(n+1)}{2}个区间。对于 a|b 则有a|b>=a 且 a|b>=b ,可以求最大值等于或值得区间,朴素的想法枚举区间求答案,通过分析 我们可以枚举 a[i]为区间最大值来找区间。两边枚举区间或值相同的,或具有单调性,所以可以二分枚举。但要注意,若两边没有约束,枚举[1, i ] [i , n] 就必定有重复举个例子:

3 2 3 2 3 2 3  若设i=3 L=1,R=7 若i=5 L=1,R=1显然我们重复算了[1,3] ,这启发我们左端点知道 L[i]+1,L[i] 为上一个相同的数的地址。这样我们只用二分[ L[i]+1 , i  ] 和 [ i,n]区间上的答案。

求区间或的方法有很多 可以用线段树。我用的线段树,并且要用读入优化。同时要用map存 temp

#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<algorithm>
typedef long long ll;
using namespace std;
const int N=200000+10;
ll sum[N<<2],cnt;
int a[N],L[N];
int now,n;
map<int,int>temp;
inline int ls(int p){return p<<1;}
inline int rs(int p){return p<<1|1;}
inline void upd(int p){sum[p]=sum[ls(p)]|sum[rs(p)];}
inline int rd(){
	int x=0;int f=1;char s=getchar();
	while(s>'9' || s<'0') if(s=='-')f=-1,s=getchar();
	while(s>='0' && s<='9') x=x*10+s-'0',s=getchar();
	return x*f;
} 
void bt(int p,int l,int r){
	if(l==r) {sum[p]=a[l];return ;}
	int mid=(l+r)>>1;
	bt(ls(p),l,mid );
	bt(rs(p),mid+1,r);
	upd(p);
}
inline ll query(int p,int l,int r,int x,int y){
	if(x<= l && r <= y){return sum[p];}
	int mid=(l+r)>>1;
	ll ans=0;
	if(x<=mid) ans=query(ls(p),l,mid,x,y);
	if(mid<y) ans|=query(rs(p),mid+1,r,x,y);  
	return ans;
}
int main(){
	n=rd();
	for(int i=1;i<=n;i++) 
		a[i]=rd(),L[i]=temp[a[i]],temp[a[i]]=i;
	bt(1,1,n);
	for(int i=1,l,r;i<=n;i++){
		l=L[i]+1;r=i; 
		while(l<=r) {
			int mid=(l+r)>>1;
			if(query(1,1,n,mid,i)==a[i]) r=mid-1;
			else l=mid+1; 
		}
		int ansl=i-(r+1)+1;
		l=i;r=n;
		while(l<=r){
			int mid=(l+r)>>1;
			if(query(1,1,n,i,mid)==a[i]) l=mid+1;
			else r=mid-1;
		} 
		int ansr=l-1-i+1;
		cnt+=1ll*ansl*ansr;
	}
	printf("%lld\n",1ll*n*(n+1)/2-cnt);
	return 0;
}

 

posted @ 2018-11-03 22:13  Exception2017  阅读(162)  评论(0编辑  收藏  举报