题目地址:
点击打开链接
题意:
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); } }