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;

}

你可能感兴趣的:(HDU)