cf487 B. Strip

题意:

把数组切成若干段,每段长度不小于len,每段内极差不大于z。问最少切成几段。

思路:

\(f(i)\) 表示 \(1\sim i\) 最少能切成(合法的)几段,-1表示没有合法方案。

\(f(i)=\min \{ f(j):j<i,[j+1,i]的极差\le z,f(j)\neq -1 \}+1\)

显然 \(f(i)\) (除了-1外)关于 \(i\) 递增,所以只需用指针 p 维护最左即最小的 \(j\)

怎么维护区间极差呢?可以RMQ、线段树、multiset、两个堆等,RMQ的预处理也要nlogn,所以直接用最简单的multiset好了

const signed N = 1e5 + 3;
int n, z, len, a[N], f[N];
multiset<int> S;

signed main() {
    iofast;
    cin >> n >> z >> len;
    for(int i = 1; i <= n; i++) cin >> a[i];

    memset(f, -1, sizeof f), f[0] = 0;
    for(int i = 1, p = 0; i <= n; i++) {
        S.insert(a[i]);
        while(p < i && (*S.rbegin() - *S.begin() > z || f[p] == -1))
            S.erase(S.find(a[++p]));
        if(i - p >= len && f[p] != -1) f[i] = f[p] + 1;
    }

    cout << f[n];
}

posted @ 2022-03-30 22:30  Bellala  阅读(63)  评论(0)    收藏  举报