题目地址:点击打开链接
题意:Beauty(l, r) = al & al + 1 & al + 2 & ... & ar 求给定集合的任意连续子集合的Beauty(l, r) 的和
思路:一个数一个数往上加,ss[i][j]记录前面i个数,以第i个数结尾的子区间的各个&的二进制右数第j个位置的1的个数,与新加入的数按位同为1时才保留,所以二进制一位一位判断,新加入的数的二进制对应为1的位置与ss[i][j]个数求和、说的不太明白。。还是看代码比较好理解
感想:一开始看着这个题就觉得不能做,然后就做别的题,后来有别的队的A了,然后才回来看的这个题。。。好不容易想出来了方法,感觉有点思维,有点推规律、不过感觉这个题还是挺有意思的,值得写篇博客记录一下
代码:
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f;
#define mod 1000000007
long long n,T,ans,a[100005],x,ss[100005][25],k,pp[30];
int main()
{
pp[0]=1;
for(int i=1;i<=20;i++)
{
pp[i]=pp[i-1]*2;//预处理二进制各位在十进制中代表的数
}
scanf("%lld",&T);
while(T--)
{
memset(ss,0,sizeof(ss));
ans=0;
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
ans+=a[i];
}
for(int i=1;i<=n;i++)
{
x=a[i];
for(int j=0;j<=20;j++)
{
if(ss[i-1][j]!=0&&(x&1))
{//前面的以i-1位置结尾的区间的&里,二进制右面j位置也有为1的,所以与新加入的i位置的数&,第j位的值仍为1.
ss[i][j]=ss[i-1][j];
ans+=pp[j]*ss[i-1][j]; }
if(x&1) ss[i][j]++; x>>=1; //cout<<i<<" "<<j<<" "<<ss[i][j]<<" "<<ans<<endl;
if(x==0) break;
}
}
printf("%lld\n",ans);
}
}