F. High 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, wherezi = 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 equals11 = 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.
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.
Print the only integer, the number of ways to choose two different mountains.
5
3 2 1 6 5
8
4
3 3 3 3
0
In the first test case all the ways are pairs of mountains with the numbers (numbering from one):
In the second test case there are no such pairs because for any pair of mountains the height of cry from them is 3, and this height is equal to the height of any mountain.
Analysis
题目的要求很偏僻,或起来的区间?
首先题意:求出合法的二元组 ( L , R ) 的数量,L 和 R 符合这样的要求:
数列上选取第 L 和第 R 个元素,aL | aL+1 | ... ... | aR-1 | aR > max( aL~R )
即按位或的和严格大于区间 [ L , R ] 的最大值
那么首先枚举每个数字
维护该数字为最大值的区间(啊!我解释不了!自行理解!)
那么我们就得到了两个数组 L[ i ] R[ i ] ,分别表示每个元素的有效范围(有效范围指上述那个被维护的区间)
根据那个什么诡异按位或,
啊!这个破按位或,题目写了一大段!qwq
我们可以得到这个结论:
如果元素 i 和元素 j 的同一位都是 1
那么对于这一位,i 和 j 或完是没影响的
所以我们可以对于当前这个枚举出来的作为最大值的元素每一位记录第一个有影响的边界
什么意思呢
如果当前(定义它为 x )
如果 x 的当前的第 j 位为 0
那么只要向两边扫描遇到一个第 j 位为 1 的元素
这个元素和 x 按位取或所得到的数字就会大于 x,也就是对 x 有所增益
最后对所有位取一个最小的区间,在这个区间内的元素与 x 按位或得出来的结果 == x
那么就有
这里扔出第二个结论:
合法的包含 X 的区间其左右端点必跨越 x 并且必不同时处于无效区间
当然这里如果左右有一个端点是 x 也可以
那么 L 在左边的有效区间的话,只要 [ L , R ] 包含 x 或者 x 之后,那么从 L 或到 x 的结果就肯定大于 x 了
既然或到 x 就满足需求,那么 x 右边的部分就可以无脑或(这样并不会使结果变小)
所以右边的有效区间也可以以此类比,答案是 左有效区间长度 * x 及 x 右边区间长度 + x 及 x 左边区间长度 * 右有效区间
当然,这个时候需要容斥一下,把多计数的 左有效区间 * 右有效区间 减去
剩下一些细节问题可以通过对拍解决
一些实现,,,,
= =
单调栈求区间
更多问题欢迎留言
Code
1 #include<cstdio> 2 #include<iostream> 3 using namespace std; 4 5 int n,arr[505050],max_num,s_poi,stack[505050]; 6 int L[505050],R[505050],uL[505050],uR[505050]; 7 int pos,iL[505050][32],iR[505050][32],inf = 1e9; 8 long long ans = 0; 9 10 int main(){ 11 scanf("%d",&n); 12 13 for(int i = 1;i <= n;i++){ 14 scanf("%d",&arr[i]); 15 max_num = max(arr[i],max_num); 16 } 17 18 for(int i = 1;i <= n;i++){ 19 while(s_poi && arr[stack[s_poi-1]] <= arr[i]) 20 R[stack[s_poi-1]] = i-1, 21 s_poi--; 22 stack[s_poi++] = i; 23 }while(s_poi) R[stack[--s_poi]] = n; 24 25 for(int i = n;i >= 1;i--){ 26 while(s_poi && arr[stack[s_poi-1]] < arr[i]) 27 L[stack[s_poi-1]] = i+1, 28 s_poi--; 29 stack[s_poi++] = i; 30 }while(s_poi) L[stack[--s_poi]] = 1; 31 32 int len = 0; 33 for(int i = max_num;i;i >>= 1) 34 len++; 35 36 for(int j = 1;j <= len;j++){ 37 pos = 0; 38 for(int i = 1;i <= n;i++){ 39 if(arr[i] & (1<<(j-1))) pos = i,iL[i][j] = 0; 40 else iL[i][j] = pos; 41 }pos = n+1; 42 for(int i = n;i >= 1;i--){ 43 if(arr[i] & (1<<(j-1))) pos = i,iR[i][j] = n+1; 44 else iR[i][j] = pos; 45 } 46 } 47 // for(int j = len;j >= 1;j--){ 48 // for(int i = 1;i <= n;i++) 49 // printf("%d/%d ",iL[i][j],iR[i][j]); 50 // puts(""); 51 // } 52 53 for(int i = 1;i <= n;i++){ 54 uL[i] = 0,uR[i] = n+1; 55 for(int j = 1;j <= len;j++) 56 uL[i] = max(uL[i],iL[i][j]), 57 uR[i] = min(uR[i],iR[i][j]); 58 } 59 60 // for(int i = 1;i <= n;i++){ 61 // printf("%d %d %d %d ",L[i],uL[i],uR[i],R[i]); 62 // } 63 64 for(int i = 1;i <= n;i++){ 65 ans += max(0LL,1LL*(uL[i]-L[i]+1)*(R[i]-i+1))+max(0LL,1LL*(i-L[i]+1)*(R[i]-uR[i]+1)); 66 ans -= max(1LL*(R[i]-uR[i]+1)*(uL[i]-L[i]+1),0LL); 67 // printf(" ",1LL*(uL[i]-L[i]+1)*(R[i]-i+1),1LL*(i-L[i]+1)*(R[i]-uR[i]+1),1LL*(R[i]-uR[i]+1)*(uL[i]-L[i]+1),ans); 68 } 69 70 cout << max(ans,0LL) << endl; 71 72 return 0; 73 }
感谢 Czl 大佬qwq