http://acm.hdu.edu.cn/showproblem.php?pid=4737
网络赛时,被暴力水过 了, 数据 有点弱吧,O(n^2) 10W的数据都过去了。。。。。。。
之后,寻找正解, 好像 二分+一些预处理 可做。。 不过这个时间比 暴力的时间还长。。。
据说还有什么双指针扫描。。的做法
暴力 code :
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
#include<vector>
using namespace std;
#define INF 100000000
int t,n,m;
int num[100005];
int main()
{
//freopen("in.txt","r",stdin);
int i,j,k;
int time=0;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
scanf("%d",&num[i]);
int tmp,cou=0;
for(i=1;i<=n;i++)
{
tmp=num[i];
if(tmp<m) cou++;
else continue;
for(j=i+1;j<=n;j++)
{
tmp=tmp|num[j];
if(tmp<m) cou++;
else break;
}
}
printf("Case #%d: %d\n",++time,cou);
}
return 0;
}
二分的做法是 ,预处理 c[i][j] ( 从第一个数到第 j个数,中二进制第i位为1 的个数) 由于或运算 使值是单调递增(非递减的) 枚举i (1到n) 二分上限 ,判断i 到mid 的数是否满足<m 详见代码
code
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
#include<vector>
using namespace std;
#define INF 100000000
int t,n,m;
int num[100005],c[40][100005];
int test(int x,int mid)
{
int i,j,k;
int tmp=0;
for(i=1;i<=30;i++)
{
if(c[i][mid]-c[i][x-1]>0) tmp+=(1<<(i-1));
}
if(tmp<m) return 1;
return 0;
}
int main()
{
//freopen("in.txt","r",stdin);
int i,j,k,time=0;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
scanf("%d",&num[i]);
for(i=1;i<=30;i++) c[i][0]=0;
for(i=1;i<=30;i++)
{
for(j=1;j<=n;j++)
{
int tmp=(num[j]>>(i-1))&1;
c[i][j]=c[i][j-1]+tmp;
}
}
int ans=0;
for(i=1;i<=n;i++)
{
int le,ri,mid;
le=i; ri=n;
while(le<=ri)
{
mid=(le+ri)>>1;
if(test(i,mid)) le=mid+1;
else ri=mid-1;
}
ans+=(le-i);
}
printf("Case #%d: %d\n",++time,ans);
}
return 0;
}