题意:定义
f(i,j)=a[i]|a[i+1]|.....|a[j]
问有多少对i ,j满足
f(i,j)
小于m
思路1:第一种思路是暴力加剪枝(竟然过了),由于当i不变的时候,j增加的时候,
f(i,j)
是递增的。所以可以直接退出
#include<bits/stdc++.h>
#define maxn 111111
using namespace std;
int a[maxn];
int main()
{
int t;
int n,k;
int kase=0;
scanf("%d",&t);
while(t--) {
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) {
scanf("%d",&a[i]);
}
int ans=0;
for(int i=1;i<=n;i++) {
int tmp=0;
for(int j=i;j<=n;j++) {
tmp|=a[j];
if(tmp<k) ans++;
else break;
}
}
printf("Case #%d: %d\n",++kase,ans);
}
return 0;
}
思路2:用TwoPointer来维护,将每个数都转化成二进制,然后用
c[i]
来表示当前和中第i个二进制位有多少个1,返回和时,只要
c[i]
大于0,就可以累加。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#define maxn 111111
using namespace std;
int c[33];
int a[maxn];
int add(int x,int v) {
int ans=0;
for(int i=0;i<31;i++) {
if(x&(1 << i)) {
c[i]+=v;
}
if(c[i]) ans+=(1 << i);
}
return ans;
}
int main()
{
int t;
int n,k;
int kase=0;
scanf("%d",&t);
while(t--) {
memset(c,0,sizeof c);
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) {
scanf("%d",&a[i]);
}
int l=1,r=1;
int tot=0;
while(r<=n) {
int tmp=add(a[r++],1);
while(tmp>=k) {
tmp=add(a[l++],-1);
}
tot+=r-l;
}
printf("Case #%d: %d\n",++kase,tot);
}
return 0;
}