P7809 [JRKSJ R2] 01 序列 题解

· · 题解

前言

传送门

blog

思路

Problem 1

问题一问的是最长不下降子序列的长度,在一个 01 串中的最长不下降子序列,总共有三种 000\dots000\dots111\dots111111\dots

可以把找到以上三种最长不下降子序列问题变为:

\max^r_{i =l}(\sum_{j = l}^i[a_j=0])+(\sum_{j = i + 1}^r[a_j=1])

可以看做以 i 分界,li0i + 1r1

那么我们又可以使用前缀和优化,设 sumfront_y 为从 1y0 的个数,sumback_y 为从 ny1 的个数,上式可以简化为:

\max^r_{i =l}sumfront_i-sumfront_{l-1}+sumback_i-sumback_{r + 1}

再次优化

上式中 sumfront_{l-1}sumback_{r + 1} 已经固定,所以我们要求的就是 \max^r_{i =l}sumfront_i+sumback_i

算区间最大值的我们使用 st 表优化。

AC Code

#include <bits/stdc++.h>
using namespace std;

inline int read(){
    int x = 0,f = 1;char ch = getchar();
    while (ch < '0' || ch > '9'){if(ch == '-') f = -1;ch = getchar();}
    while (ch >= '0' && ch <= '9'){x = x * 10 + ch - 48;ch = getchar();}
    return x * f;
}

int n,m;
bool a[1000010];
int sum[1000010],sum_front[1000010],sum_back[1000010];
int LOG2[1000010],st[1000010][21];

void init(){
    for(int i = 2;i <= n;++i)
        LOG2[i] = LOG2[i >> 1] + 1;
    for(int i = 1;i <= n;++i)
        st[i][0] = sum_front[i] + sum_back[i];
    int k = LOG2[n];
    for(int i = 1;i <= k;++i)
        for(int j = 1;j + (1 << i) - 1 <= n;++j)
            st[j][i] = max(st[j][i - 1],st[j + (1 << i - 1)][i - 1]);
}

int get(int l,int r){
    int s = LOG2[r - l + 1];
    return max(st[l][s],st[r - (1 << s) + 1][s]);
}

int main(){
    n = read(),m = read();
    for(int i = 1;i <= n;++i){
        a[i] = read();
        sum_front[i] = sum_front[i - 1] + (a[i] == 0);
        if(i > 1)sum[i] = sum[i - 1] + (a[i] == 1 && a[i - 1] == 0);
    }
    for(int i = n;i >= 1;--i)
        sum_back[i] = sum_back[i + 1] + (a[i] == 1);
    init();
    for(int i = 1;i <= m;++i){
        int problem,l,r;
        problem = read(),l = read(),r = read();
        if(problem == 1)
            printf("%d",get(l,r) - sum_front[l - 1] - sum_back[r + 1]);
        else 
            printf("%d",1 + !(sum[l] == sum[r]));
        puts("");
    }
}