HDU4737 - A Bit Fun(线段树)

题目大意

给你一个数组a,定义f(i,j)=ai|ai+1|ai+2|⋯|aj ,|为or运算,求满足f(i,j)<m的二元组个数,N≤105,m≤230

题解

枚举起点i,然后找出最靠右的k,使得f[i,k)<m,计算f(i,k)的值可以用线段树来维护,查询只需要logn时间,求k这个位置可以用二分法求出,总的时间复杂度为nlogn^2,刚好能够趟过。。。话说有很多人是用O(n^2)暴力每一对f(i,j),然后加上剪枝,速度奇快。。。。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define MAXN 100005
#define lson l,m,s<<1
#define rson m+1,r,s<<1|1
int sumv[MAXN<<2],a[MAXN];
void PushUp(int s)
{
    sumv[s]=sumv[s<<1]|sumv[s<<1|1];
}
void build(int l,int r,int s)
{
    if(l==r) {
        sumv[s]=a[l];
        return;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    PushUp(s);
}
int query(int ql,int qr,int l,int r,int s)
{
    if(ql<=l&&r<=qr)
        return sumv[s];
    int m=(l+r)>>1;
    int ans=0;
    if(ql<=m) ans=ans|query(ql,qr,lson);
    if(qr>m)  ans=ans|query(ql,qr,rson);
    return ans;
}
int main()
{
    int T;
    scanf("%d",&T);
    for(int t=1;t<=T;t++)
    {
        int n,m;
        long long ans=0;
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++) scanf("%d",&a[i]);
        build(0,n-1,1);
        for(int i=0;i<n;i++)
        {
            if(a[i]>=m) continue;
            int l=i,r=n-1;
            while(l<=r)
            {
                int mid=(l+r)>>1;
                int sum=query(i,mid,0,n-1,1);
                if(sum>=m) r=mid-1;
                else
                    l=mid+1;
            }
            ans+=r-i+1;
        }
        printf("Case #%d: %I64d\n",t,ans);
    }
    return 0;
}

posted on 2013-09-16 20:21  仗剑奔走天涯  阅读(197)  评论(0编辑  收藏  举报

导航