Subarrays Beauty (位运算)解题报告

A. Subarrays Beauty
time limit per test
1.0 s
memory limit per test
256 MB
input
standard input
output
standard output

You are given an array a consisting of n integers. A subarray (l, r) from array a is defined as non-empty sequence of consecutive elements al, al + 1, ..., ar.

The beauty of a subarray (l, r) is calculated as the bitwise AND for all elements in the subarray:

Beauty(l, r) =  al  &  al + 1  &  al + 2  &  ...  &  ar

Your task is to calculate the summation of the beauty of all subarrays (l, r) (1 ≤ l ≤ r ≤ n):

Input

The first line contains an integer T, where T is the number of test cases.

The first line of each test case contains an integer n (1 ≤ n ≤ 105), where n is the size of the array a.

The second line of each test case contains n integers a1, a2, ..., an (1 ≤ ai ≤ 106), giving the array a.

Output

For each test case, print a single line containing the summation of the beauty of all subarrays in the given array.

Example
input
Copy
2
3
7 11 9
4
11 9 6 11
output
40
48
Note

As input/output can reach huge size it is recommended to use fast input/output methods: for example, prefer to use scanf/printfinstead of cin/cout in C++, prefer to use BufferedReader/PrintWriter instead of Scanner/System.out in Java.

bitwise AND takes two equal-length binary representations and performs the logical AND operation on each pair of the corresponding bits, by multiplying them. Thus, if both bits in the compared position are 1, the bit in the resulting binary representation is 1 (1  ×  1 = 1); otherwise, the result is 0 (1  ×  0 = 0 and 0  ×  0 = 0). This operation exists in all modern programming languages, for example in language C++ and Java it is marked as &.

In the first test case, the answer is calculated as summation of 6 subarrays as follow:

Beauty(1, 1) + Beauty(l, 2) + Beauty(1, 3) + Beauty(2, 2) + Beauty(2, 3) + Beauty(3, 3)

                                            (7) + (7  & 11) + (7  & 11  & 9) + (11) + (11  & 9) + (9) = 40

http://codeforces.com/gym/101532/problem/A
题意:给定长度为n的数,要求求所有子区间内的数进行与运算(&)的和;
解题报告:

对于一个数来说变成二进制的后可以变成二进制数位之和,例如:
    7=1*2^0+1*2^1+1*2^2;  11=1*2^0+1*2^1+0*2^3+1*2^4;
因此根据与运算特性一旦出现了0&前面的数一定会变成0,要重新开始算,再讨论所有区间就完了。拿样例1来说:
a[1]=7,a[2]=9,a[3]=11可以看成
a[1]=0111
a[2]=1001
a[3]=1011
对于二进制第j位a[i][j-1],假设在区间(l,r)都是连续的1,因此这个区间内1的个数是(r-l+1)*(r-l+2)/2。
我们看看样例的第一个二进制位是111,区间是(1,3),它的子区间分别是(1,1)(1,2)(1,3)(2,2)(2,3)(3,3)也可以写成
(1,1)(2,1)(2,2)(3,1)(3,2)(3,3)(这里只是数的方向不同),因此公式就出来了。
下面代码(里面有个通过对数直接取最大二进制位数的优化,不知道为什么我用C++一定会超时,换了c直接a了)

#include<iostream>
#include<stdio.h>
#include<bitset>
#include<cmath>
using namespace std;
const int maxn=1e5+5;
bitset<31>a[maxn];
int main()
{
	int T;
	while(scanf("%d",&T)!=EOF)
	{
		while(T--)
		{
			int n,temp;
			int set=0;
			scanf("%d",&n);
			for(int i=0;i<n;i++)
			{
				scanf("%d",&temp);
				set=max(set,(int)log2(temp)+1);
				a[i]=bitset<31>(temp);
			}
			long long ans=0;
			a[n]=bitset<31>(0);
			for(int i=0;i<set;i++)
			{
				long long rco=0;
				int  flag=0;
//				cout<<"+++++++=flag="<<flag<<endl;
				for(int j=0;j<n+1;j++)
				{
					if(flag==0)
					{
						if(a[j][i]==1)
						{
							rco++;
							flag=1;
						}
					}
					else
					{
						if(a[j][i]==1)
						{
							rco++;
						}
						else
						{
							flag=0;
							ans+=(1<<i)*(long long)rco*(rco+1)/2;
							rco=0;
						}
					}
//					cout<<"j="<<j<<" "<<"flag="<<flag<<" "<<rco<<" "<<ans<<endl;
				}
//				cout<<"--------------------"<<endl;
			}
			cout<<ans<<endl;
		}
	}
 } 

猜你喜欢

转载自blog.csdn.net/weixin_40859716/article/details/79608318