Subarrays Beauty (位运算)解题报告

本文介绍了一道算法题目,要求计算给定整数数组的所有子区间中元素按位与运算结果之和的方法。通过分析与运算特性,采用二进制位处理技巧,实现了高效的求解算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;
		}
	}
 } 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值