题意:
给出了一列数..定义(i,j)为第i个数开始一次做或运算到最后一个数..问比给定的m小的(i,j)有多少对...
题解:
因为或运算时单调的...所以可以用各种方法了..比如两个指针扫过去..而我用的是二分..做了预处理后..枚举i..二分找出j的最大位置...
Program:
#include<iostream>
#include<stack>
#include<queue>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<cmath>
#define ll long long
#define oo 1000000007
#define eps 1e-5
#define MAXN 100010
using namespace std;
int s[100005][32];
ll ans;
bool judge(int r,int l,int p)
{
int i;
if (l<0) l=0;
ll k=1,ans=0;
for (i=1;i<=30;i++)
{
if (s[r][i]-s[l][i]) ans+=k;
k*=2;
}
if (ans<p) return true;
return false;
}
int main()
{
int C,cases,i,n,x,k,p;
scanf("%d",&C);
for (cases=1;cases<=C;cases++)
{
scanf("%d%d",&n,&p);
memset(s,0,sizeof(s));
for (i=1;i<=n;i++)
{
memcpy(s[i],s[i-1],sizeof(s[i]));
scanf("%d",&x),k=0;
while (x)
{
k++;
s[i][k]=s[i-1][k]+x%2;
x>>=1;
}
}
ans=0;
for (i=1;i<=n;i++)
{
int l=i-1,r=n+1,mid;
while (r-l>1)
{
mid=r+l>>1;
if (judge(mid,i-1,p)) l=mid;
else r=mid;
}
ans+=l-i+1;
}
printf("Case #%d: %I64d\n",cases,ans);
}
return 0;
}