链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1674
两个多小时写出来这个题好开心撒。
思路:我们对于位置i 的数,考虑以这个数结尾的区间的价值。 考虑他的每一个二进制位,如果第j 位 的二进制是0 那么这一位就不用管了, 因为与起来肯定是0 的,所以这一位去乘以 别的位肯定也是0 所以我们只考虑 数a[i] 的二进制为 1 的位,如果该位为1,那么我只需要找到该位的第一个为0 的位置在哪里,因为在这个位置之前的肯定与起来肯定是0 所以只考虑 [in, i ] [in+1,i] [in+2,i ] ...... 这些区间,同时还要满足或的情况,那么肯定就是 考虑当前位 第一为1 的位置在哪里。 然后就做出来了。
还用了个输入挂。。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
// 外挂 1
template <class T>
bool scan_d(T &ret)
{
char c;
int sgn;
T bit = 0.1;
if (c=getchar(), c==EOF)
{
return 0;
}
while (c!='-'&& c!='.'&& (c<'0'||c>'9'))
{
c = getchar();
}
sgn = (c == '-') ? -1 : 1;
ret = (c == '-') ? 0 : (c - '0');
while (c = getchar(), c >= '0' && c <= '9')
{
ret = ret * 10 + (c - '0');
}
if (c == ' ' || c == '\n')
{
ret *= sgn;
return 1;
}
while (c = getchar(), c >= '0' && c <= '9')
{
ret += (c - '0') * bit, bit /= 10;
}
ret *= sgn;
return 1;
}
template <class T>
inline void print_d(T& x)
{
if (x > 9)
{
print_d(x/10);
}
putchar(x % 10 + '0');
}
const int N =1e5+5;
const ll mod=1e9+7;
int a[N];
int flag[N][40];
int sum[N][40];
int pre1[N][40];
int pre2[N][40];
int n;
ll yi[40];
void init_yi()
{
yi[0]=1;
for(int i=1;i<=65;i++) yi[i]=yi[i-1]*2%mod;
}
void zhuan(int i)
{
int x=a[i];
int cnt=0;
while(x)
{
sum[i][++cnt]=x%2;
flag[i][cnt]=x%2;
x/=2;
}
}
void getpre()
{
for(int i=1;i<=n;i++){
for(int j=1;j<=35;j++){
sum[i][j]=sum[i-1][j]+sum[i][j];
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=35;j++)
{
if(flag[i][j])
{
int l,r,mid;
int in=0;
l=1; r=i;
while(l<=r)
{
mid=(l+r)>>1;
if(sum[i][j]-sum[mid-1][j]==i-mid+1)
{
in=mid;
r=mid-1;
}
else l=mid+1;
}
pre1[i][j]=in;// 找到前边第一个 0 in-1 为第一个0 的位置
}
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=35;j++)
{
int l,r,mid;
int in=0;
l=1; r=i;
while(l<=r)
{
mid=(l+r)>>1;
if(sum[i][j]-sum[mid-1][j]!=0)
{
in=mid;
l=mid+1;
}
else r=mid-1;
}
pre2[i][j]=in;// 找到前边第一个 1 in 为第一个1 的位置
}
}
}
int main()
{
init_yi();
scan_d(n);
for(int i=1;i<=n;i++)
{
scan_d(a[i]);
zhuan(i);
}
getpre();
ll ans=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=35;j++)
{
if(flag[i][j]==1)
{
int l,r,mid;
int in=pre1[i][j];
ll cnt=i-in+1;
for(int k=1;k<=35;k++)
{
if(sum[i][k]-sum[in-1][k]!=0)
{
int in1=pre2[i][k];
ll tmp=in1-in+1;
ll num=yi[j-1]*yi[k-1]%mod;
ans=(ans+tmp*num%mod)%mod;
}
}
// printf("L %d R %d\n",in,i);
// printf("** i %d j %d ans %lld\n",i,j,ans);
}
}
}
printf("%lld\n",ans);
return 0;
}