zoukankan      html  css  js  c++  java
  • codeforces 875D

    http://codeforces.com/contest/875/problem/D

    题意:给你 n 个长度的数组,求一共有多少区间 [ l ,  r ] ,使区间 [ l ,  r ] 所有数字的 或 运算大于所有区间 [ l ,  r ] 的数。

    题解:RMQ+分治。

       找到 区间 [ l ,  r ] 内最大值 a,和最接近 a 的数 b 且(b|a>a),左边的数为 lb,右边的数为rb,经过 a 的区间可以 o(1)求出。分治 a 的两边。

    #include<cstdio>
    #include<string>
    #include<cmath>
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<set>
    #define oo 0x3f3f3f3f
    #define mod 1000000007
    using namespace std;
    const int MAXN = 200000+10;
    int dp[MAXN][20];
    int a[MAXN];
    vector<int> ve[35];
    void RMQ_max_init( int n )
    {
        memset(dp, 0x00, sizeof(dp));
        for(int i = 1; i <= n; i++)
            dp[i][0] = i;
        for(int j = 1; (1<<j) <= n; j++)
            for(int i = 1; i+(1<<j)-1 <= n; i++)
                if( a[ dp[i][j-1] ] < a[ dp[i+(1<<(j-1))][j-1] ])
                    dp[i][j] = dp[i+(1<<(j-1))][j-1];
                else
                    dp[i][j] = dp[i][j-1];
    }
    int RMQ_max( int L, int R )
    {
        int k = 0;
        while( (1<<(k+1)) <= R-L+1 )
            k++;
        if(a[ dp[L][k] ] < a[ dp[R-(1<<k)+1][k] ]) return dp[R-(1<<k)+1][k];
        return dp[L][k];
    }
    void init(int x, int id)
    {
        for(int i = 0; (1<<i) <= x; ++i)
        {
            if(x&(1<<i)) ve[i].push_back(id); 
        }
    }
    long long ans;
    void dfs(int l, int r, int n)
    {
        if(l>=r) return ;
        int mid = RMQ_max(l, r);
        int left = 0, right = n+1;
        for(int i = 0; (1<<i)<=1e9; ++i)
        {
            if(!(a[mid]&(1<<i)))
            {
                int k = lower_bound(ve[i].begin(), ve[i].end(), mid)-ve[i].begin();
                if(k < ve[i].size() && ve[i][k]>mid) right = min(right, ve[i][k] );
                --k;
                if(k>=0 && k < ve[i].size() && ve[i][k] < mid) left = max(left, ve[i][k]);
            }
        }
        if(left != 0 && left >= l)
        {
            ans += (long long)(left-l+1)* (long long)(r-mid+1);
        }
        if(right != n+1 && right <= r)
        {
            ans += (long long)(mid-l+1)* (long long)(r-right+1);
        }
        if(left != 0 && left >= l && right != n+1 && right <= r)
        {
            ans -= (long long)(left-l+1)* (long long)(r-right+1);
        }
        dfs(l, mid-1, n);
        dfs(mid+1, r, n);
    }
    int main (void)
    {
        ios::sync_with_stdio(false);
        int n; cin >> n; 
        for(int i = 1; i <= n; ++i)
        {
            cin >> a[i];
            init( a[i], i );
        }
        RMQ_max_init(n);
        ans = 0;
        dfs(1, n, n);
        cout << ans;
    }
  • 相关阅读:
    7多态与异常处理的课上作业
    软工概论第十五周总结
    构建之法阅读笔记之三
    小组项目冲刺第六天的个人总结
    书店促销
    小组项目冲刺第五天的个人总结
    找水王
    软工概论第十四周总结
    动态规划——买书问题
    小组项目冲刺第四天的个人总结
  • 原文地址:https://www.cnblogs.com/lkcc/p/7683969.html
Copyright © 2011-2022 走看看