zoukankan      html  css  js  c++  java
  • noip模拟赛 区间

    分析:要遍历所有的区间,肯定是枚举左端点,然后再枚举右端点.关键是怎么高效地求区间&,|,一般而言是用前缀和的,但是&,|不满足区间可减性,所以可以考虑线段树?这道题不带修改操作,用线段树太浪费了,那么可以用ST表来维护.

          查询做到O(1)了,但是怎么快速枚举区间呢?枚举左端点和右端点肯定只能选择一个优化,优化枚举右端点的循环.观察数据范围,100000,很容易想到二分.可以每次固定左端点,然后二分右端点的位置.因为&操作随着区间数的增加而答案减少,|是增加,都满足单调性,所以求满足两个条件的区间的交,统计一下区间的元素个数有多少个就可以了.

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    const long long inf = 1LL << 60, mod = 1e9 + 7;
    
    typedef long long ll;
    
    ll n, a, b, c, d, f1[100010][22], f2[100010][22], s[100010], ans;
    
    void init()
    {
        for (int j = 1; j <= 21; j++)
            for (int i = 1; i + (1 << j) - 1 <= n; i++)
            {
                f1[i][j] = f1[i][j - 1] & f1[i + (1 << (j - 1))][j - 1];
                f2[i][j] = f2[i][j - 1] | f2[i + (1 << (j - 1))][j - 1];
            }
    }
    
    ll query(ll l, ll r,ll op)
    {
        ll k = (ll)((log(r - l + 1)) / log(2.0));
        if (op == 1)
            return f1[l][k] & f1[r - (1 << k) + 1][k];
        else
            return f2[l][k] | f2[r - (1 << k) + 1][k];
    }
    
    int main()
    {
        scanf("%lld%lld%lld%lld%lld", &n, &a, &b, &c, &d); 
        for (int i = 1; i <= n; i++)
        {
            scanf("%lld", &s[i]);
            f1[i][0] = f2[i][0] = s[i];
        }
        init();
        for (int i = 1; i <= n; i++)
        {
            ll l = i, r = n, temp1 = inf, temp2 = -inf, temp3 = inf, temp4 = -inf;
            while (l <= r)
            {
                ll mid = (l + r) >> 1;
                if (query(i, mid,1) >= a)
                {
                    l = mid + 1;
                    temp2 = mid;
                }
                else
                    r = mid - 1;
            }
    
            l = i, r = n;
            while (l <= r)
            {
                ll mid = (l + r) >> 1;
                if (query(i, mid, 1) <= b)
                {
                    r = mid - 1;
                    temp1 = mid;
                }
                else
                    l = mid + 1;
            }
    
            l = i, r = n;
            while (l <= r)
            {
                ll mid = (l + r) >> 1;
                if (query(i, mid, 2) >= c)
                {
                    r = mid - 1;
                    temp3 = mid;
                }
                else
                    l = mid + 1;
            }
    
            l = i, r = n;
            while (l <= r)
            {
                ll mid = (l + r) >> 1;
                if (query(i, mid, 2) <= d)
                {
                    l = mid + 1;
                    temp4 = mid;
                }
                else
                    r = mid - 1;
            }
            ll ll = max(temp1, temp3), rr = min(temp2, temp4);
            ans += max((long long)0, rr - ll + 1);
            ans %= mod;
        }
        printf("%lld
    ", ans);
    
        return 0;
    }
  • 相关阅读:
    ORA-02290: 违反检查约束条件
    上传图片
    dart视频教程
    'OFFSET' 附近有语法错误。 在 FETCH 语句中选项 NEXT 的用法无效。
    .net js有数据 但是跳转不到操作页
    LAYUI layedit 富文本框内容的取值
    LAYUI select 下拉框得高度
    防止页面刷新
    Hadoop常用命令
    spark常用命令
  • 原文地址:https://www.cnblogs.com/zbtrs/p/7774778.html
Copyright © 2011-2022 走看看