2019HDU多校 Round10

11 Make Rounddog Happy (启发式分治)

题意:1e5个数 统计多少个区间满足 区间最大 - 区间长度 <= k 且区间内没有相同的数

题解:都说这个题是这种套路.... 用st表预处理区间最大值 然后再预处理每个数往左往右没有相同数的最远距离

   然后每次找到区间最大值 暴力从区间小的一边枚举答案 然后分治

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 1e6 + 5;
ll ans;
int n, K;
int a[MAXN];
int st[MAXN][21], lg[MAXN];
int L[MAXN], R[MAXN];
int vis[MAXN];

void solve(int l, int r) {
    if(l > r) return;

    int k = lg[r - l + 1];
    int pos;
    if(a[st[l][k]] >= a[st[r - (1 << k) + 1][k]]) pos = st[l][k];
    else pos = st[r - (1 << k) + 1][k];

    if(pos - l <= r - pos) {
        for(int i = l; i <= pos; i++) {   //枚举左端点
            int rr = a[pos] - K + i - 1;  //移项之后 满足rr <= 区间右端点就是满足题意的
            rr = max(rr, pos);            //大于pos 最大值才成立

            int tr = min(R[i], r);
            if(tr >= rr) ans += 1LL * (tr - rr + 1);
        }
    } else {
        for(int i = r; i >= pos; i--) {
            int ll = K - a[pos] + i + 1;
            ll = min(ll, pos);

            int tl = max(L[i], l);
            if(tl <= ll) ans += 1LL * (ll - tl + 1);
        }
    }
    solve(l, pos - 1); solve(pos + 1, r);
}

int main() {
    lg[0] = -1;
    for(int i = 1; i <= MAXN - 2; i++) lg[i] = lg[i >> 1] + 1;

    int T;
    scanf("%d", &T);
    while(T--) {
        ans = 0;
        scanf("%d%d", &n, &K);
        for(int i = 1; i <= n; i++) scanf("%d", &a[i]), st[i][0] = i;

        for(int i = 1; i <= 20; i++)
            for(int j = 1; j <= n + 1 - (1 << i); j++) {
                if(a[st[j + (1 << (i - 1))][i - 1]] >= a[st[j][i - 1]]) st[j][i] = st[j + (1 << (i - 1))][i - 1];
                else st[j][i] = st[j][i - 1];
            }

        memset(vis, 0, sizeof(vis)); L[1] = 1; vis[a[1]] = 1;
        for(int i = 2; i <= n; i++) {
            if(vis[a[i]]) L[i] = max(L[i - 1], vis[a[i]] + 1);
            else L[i] = L[i - 1];
            vis[a[i]] = i;
        }

        memset(vis, 0, sizeof(vis)); R[n] = n; vis[a[n]] = n;
        for(int i = n - 1; i >= 1; i--) {
            if(vis[a[i]]) R[i] = min(R[i + 1], vis[a[i]] - 1);
            else R[i] = R[i + 1];
            vis[a[i]] = i;
        }
        solve(1, n);
        printf("%lld\n", ans);
    }
    return 0;
}
Make Rounddog Happy

猜你喜欢

转载自www.cnblogs.com/lwqq3/p/11449279.html