您的位置:首页 > 理论基础 > 计算机网络

HDU 4737 A Bit Fun 2013成都 网络赛 1010

2013-09-14 21:59 441 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4737

题目大意:给定一系列数,F(i,j)表示对从ai到aj连续求或运算,(i<=j)求F(i,j)<=m的总数。

解题思路:或运算只会让值变大或保持不变。不断通过右移j来更新F(i,j),当aj>=m时所有的i<=j F(i,j)都大于等于m,因此从j后面继续扫数组;当aj<m而F(i,j)>=m时通过右移i来使F(i,j)<m。扫完整个数组即可。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
int tmp[32],last;
long long A[100005];
long long m,now;
int n;
void getin(long long x)
{
int i=0;
while(x)
{
if(x&1)
tmp[i]++;
x/=2;
i++;
}
if(last<i-1)
last=i-1;
return;
}
void Minus(int i)
{
int k=0;
long long x=A[i];
while(x){
if(x%2)
tmp[k]-=1;
x/=2;
k++;
}
return;
}
long long getnow()
{
int i;
long long x=1;
long long s=0;
for(i=0;i<=30;i++)
{
if(tmp[i]>0)
s+=x;
x*=2;
}
return s;
}
int geti(int i,long long Now)
{
while(Now>=m){
Minus(i);
i++;
Now=getnow();
}
now=Now;
return i;
}
void pls(int j)
{
int k;
long long x=A[j];
for(k=0;k<=30;k++)
{
if(x%2)
tmp[k]+=1;
x/=2;
}
return;
}
int main()
{
int Case=1;
int t,i,j,sum;
scanf("%d",&t);
while(t--)
{
sum=0;
scanf("%d%I64d",&n,&m);
for(i=0;i<n;i++)scanf("%I64d",&A[i]);
i=j=0;
while(j<n)
{
while(j<n&&A[j]>=m)
j++;
if(j>=n)
break;
i=j;
sum++;
memset(tmp,0,sizeof(tmp));
last=1;
now=A[i];
getin(A[i]);
if(j+1>=n)
{
j++;
}
while(j<n){
if(A[++j]>=m||j>=n){
break;
}
else
{
if((A[j]|now)>=m)
{
pls(j);
i=geti(i,now|A[j]);
sum+=j-i+1;
}
else
{
sum+=j-i+1;
pls(j);
now=A[j]|now;
}
}
}
}
printf("Case #%d: ",Case++);
printf("%d\n",sum);
}
return 0;
}


View Code

想思路的时候想复杂了,需要右移i时,其实可以直接从j开始向前找到最小的i使F(i,j)<m。不需要像我一样开数组记录
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: