嘘~ 正在从服务器偷取页面 . . .

CF689D Friends and Subsequences 题解


CF689D Friends and Subsequences 题解

题目链接:CF689D Friends and Subsequences

题意

  • 给定序列 \(a\) 和序列 \(b\),长度均为 \(n\)。问有多少组 \((l,r)\),满足 \(1\le l\le r\le n\)\(\displaystyle \max_{i=l}^r a_i=\min_{i=l}^r b_i\)
  • \(1\le n\le 2\times 10^5\)\(|a_i|,|b_i|\le 10^9\)

输入格式

The first line contains only integer \(n\) (\(1\leq n\leq 200000\)).

The second line contains \(n\) integer numbers \(a_{1}, a_{2}, \ldots, a_{n}\) (\(-10^9 \leq a_i \leq 10^9\)) — the sequence \(a\).

The third line contains \(n\) integer numbers \(b_{1}, b_{2}, \ldots, b_{n}\) (\(-10^9 \leq b_i \leq 10^9\)) — the sequence \(b\).

输出格式

Print the only integer number — the number of occasions the robot will count, thus for how many pairs \(\displaystyle \max _{i=l}^r a_i=\min _{i=l}^r b_i\) is satisfied.

注意到当左端点固定时,\(a\) 最大值减 \(b\) 最小值的差会单调不降。

容易想到这样的做法:枚举合法区间的左端点,然后二分一个右端点。然而这个做法是错的。

假设 \([l,r]\) 是一个极大合法的区间,且区间 \([p,l-1]\) 不合法。而此时 \([p,l]\)可能是一个合法区间。

于是考虑枚举左端点 \(l\) ,接着做两个二分,得到以 \(l\) 为左端点的极大合法区间的范围 \([l^{\prime},r^{\prime}]\)

则对于任意整数 \(x \in [l^{\prime}, r^{\prime}]\) ,区间 \([l,x]\) 为合法区间,并且 \(l^{\prime}\) 是最左侧的那个,\(r^{\prime}\) 是最右侧的那个。

实现的话,因为不带修改,所以可以用 ST表 解决,线段树二分有空再写吧

时间复杂度 \(\mathcal{O}(n \log n)\)

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(2e5 + 5))
#define LN 20

int n,res,lg[N],f1[LN][N],f2[LN][N];
int qmax(int l,int r)
{
    int k = lg[r - l + 1];
    return max(f1[k][l], f1[k][r - (1 << k) + 1]);
}
int qmin(int l,int r)
{
    int k = lg[r - l + 1];
    return min(f2[k][l], f2[k][r - (1 << k) + 1]);
}
int ql(int i)
{
    int l = i, r = n;
    while(l < r)
    {
        int mid = (l + r + 1) >> 1;
        if(qmax(i,mid) <= qmin(i,mid)) l = mid;
        else r = mid - 1;
    }
    if(l <= n && qmax(i,l) == qmin(i,l)) return l;
    return 0;
}
int qr(int i)
{
    int l = i, r = n;
    while(l < r)
    {
        int mid = (l + r) >> 1;
        if(qmax(i,mid) >= qmin(i,mid)) r = mid;
        else l = mid + 1;
    }
    if(r > 0 && qmax(i,r) == qmin(i,r)) return r;
    return 0;
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> n;
    for(int i = 2; i <= n; i++) lg[i] = lg[i >> 1] + 1;
    for(int i = 1; i <= n; i++) cin >> f1[0][i];
    for(int i = 1; i <= n; i++) cin >> f2[0][i];
    for(int j = 0; 1 << (j + 1) <= n; j++)
    {
        int *f = f1[j], *g = f1[j + 1];
        for(int i = 1; i + (1 << j) - 1 <= n; i++)
            g[i] = max(f[i], f[i + (1 << j)]);
        f = f2[j], g = f2[j + 1];
        for(int i = 1; i + (1 << j) - 1 <= n; i++)
            g[i] = min(f[i], f[i + (1 << j)]);
    }
    for(int i = 1; i <= n; i++)
    {
        int l = ql(i), r = qr(i);
        if(!l || !r) continue; if(l > r) swap(l,r);
        res += (r - l + 1);
    }
    cout << res << '\n';
    return 0;
}

文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录