zoukankan      html  css  js  c++  java
  • Friends and Subsequences

    传送门
    很棒的题。
    有两个序列a和b,长度都为n,对于a序列需要知道区间的最大值,对于b序列需要知道区间的最小值
    求出符合式子
    (max_{i = l}^ra_i = min_{i = l}^rb_i)
    的所有区间个数。

    方法很简单,用st表分别维护a序列的最大值的b序列的最小值,明显,a序列的st表是一个递增函数,b序列的st表是一个递减函数
    令a序列的st表减去b序列的st表,那么这个值也是递增的,如果说,值是0,那么久满足题目的情况。
    那么遍历左区间,进行二分,用st表(O(1))查询找到0最后一次出现的位置和第一次出现的位置,那么答案就是[左区间, 右区间2 - 右区间1 + 1],都是满足情况的
    时间复杂度(O(nlogn))

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #define ll long long
    using namespace std;
    const int N = 2e5 + 5;
    int a[N], b[N], n, k;
    int MAX[N][20], MIN[N][20];
    void init(){
        memset(MIN, 0x3f, sizeof(MIN));
        memset(MAX, 0, sizeof(MAX));
        for(int i = 1; i <= n; i++){
            MAX[i][0] = a[i];
            MIN[i][0] = b[i];
        }
    
        for(int j = 1; j <= 20; j++)
            for(int i = 1; i + (1 << j) - 1 <= n; i++){
                MIN[i][j] = min(MIN[i][j - 1], MIN[i + (1 << (j - 1))][j - 1]);
                MAX[i][j] = max(MAX[i][j - 1], MAX[i + (1 << (j - 1))][j - 1]);
            }
    }
    int Query(int l, int r){
        int k = log2(r - l + 1);
        return max(MAX[l][k], MAX[r - (1 << k) + 1][k]) - min(MIN[l][k], MIN[r - (1 << k) + 1][k]);
    }
    void solve(){
        scanf("%d", &n);
        for(int i = 1; i <= n; i++)
            scanf("%d", &a[i]);
        for(int i = 1; i <= n; i++)
            scanf("%d", &b[i]);
        ll ans = 0;
        init();
        for(int i = 1; i <= n; i++){
            int l = i, r = n, mid;
            while(l <= r){
                mid = (l + r) >> 1;
                int now = Query(i, mid);
                if(now > 0) r = mid - 1;
                else l = mid + 1;
            }
            ans += r - i + 1;//[i, r] 都是 ≤ 0的
            l = i, r = n;
            while(l <= r){
                mid = (l + r) >> 1;
                int now = Query(i, mid);
                if(now < 0) l = mid + 1;
                else r = mid - 1;
            }
            ans -= r - i + 1;//[i, r] 都是 ≥ 0的
        }
        printf("%lld
    ", ans);
    }
    int main(){
        solve();
        return 0;
    }
    
  • 相关阅读:
    用fiddler测试ip轮询
    ubuntu下安装fiddler
    Andriod相机开发关于startPreview Failed的错误的特别记录(重要)
    我的Cocos2dx开发模式
    Android WebView导入HTML使Js生效的方法
    Lua快捷键
    String,StringBuilder,StringBuffer的对比测试
    重构视角(摘抄)
    String属于“假引用类型”,代码为证(一个String引发的血案...)
    static class
  • 原文地址:https://www.cnblogs.com/Emcikem/p/13199252.html
Copyright © 2011-2022 走看看