BZOJ4241: 历史研究

题目地址

题目连接php

题解

经典大分块..不过挺好写的。就写了半个小时左右。
处理出数组

  • \(ans[i][j]\)表示块\(i\)到块\(j\)的答案
  • \(cnt[i][j]\)表示块\(1\)到块\(i\)中数\(j\)的出现次数(要先离散化)

预处理这两个数组都离散化后利用一个桶就能够了。
考虑每一个询问\([l,r]\)的答案可能的来源,首先确定\(ans[l][r]\)是其中的一个候选项,而后两个边界块中的数也都是可能的候选项。那么枚举这两个块中的数,利用\(cnt\)数组和一个桶便可解决。
复杂度\(O(n \sqrt{n})\)spa

#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

typedef long long ll;
const int N = 100010;
const int M = 320;

inline void read(int &x) {
    x = 0; char c = getchar();
    while(c < '0' || c > '9') c = getchar();
    while(c >= '0' && c <= '9') {
        x = x * 10 + c - '0';
        c = getchar();
    }
} 

ll ans[M][M];
int bl[N], L[M], R[M], cnt[M][N];
int a[N], b[N], c[N], tong[N];
int n, m, block, siz;

void init() {
    siz = sqrt(n);
    block = n / siz;
    if(n % siz) ++block;
    for(int i = 1; i <= n; ++i) {
        bl[i] = (i - 1) / siz + 1;
    }
    for(int i = 1; i <= block; ++i) {
        L[i] = (i - 1) * siz + 1;
        R[i] = i * siz;
    }
    R[block] = n;
    for(int i = 1; i <= block; ++i) {
        for(int j = L[i]; j <= R[i]; ++j) cnt[i][a[j]]++;
    }
    for(int j = 1; j <= n; ++j) for(int i = 1; i <= block; ++i) 
            cnt[i][j] += cnt[i - 1][j];
    for(int i = 1; i <= block; ++i) {
        for(int k = L[i]; k <= R[i]; ++k) {
            tong[a[k]]++;
            ans[i][i] = max(ans[i][i], 1ll * tong[a[k]] * c[k]);
        }
        for(int j = i + 1; j <= block; ++j) {
            ans[i][j] = ans[i][j - 1];
            for(int k = L[j]; k <= R[j]; ++k) {
                tong[a[k]]++;
                ans[i][j] = max(ans[i][j], 1ll * tong[a[k]] * c[k]);
            }
        }
        for(int j = L[i]; j <= n; ++j) tong[a[j]] = 0;
    }
}

ll solve(int l, int r) {
    ll Ans = 0;
    if(bl[l] == bl[r] || bl[r] == bl[l] + 1) {
        for(int i = l; i <= r; ++i) {
            tong[a[i]]++;
            Ans = max(Ans, 1ll * tong[a[i]] * c[i]);
        }
        for(int i = l; i <= r; ++i) tong[a[i]] = 0;
        return Ans;
    }
    Ans = ans[bl[l] + 1][bl[r] - 1];
    for(int i = l; i <= R[bl[l]]; ++i) {
        tong[a[i]]++;
        Ans = max(Ans, 1ll * (tong[a[i]] + cnt[bl[r] - 1][a[i]] - cnt[bl[l]][a[i]]) * c[i]);
    }
    for(int i = L[bl[r]]; i <= r; ++i) {
        tong[a[i]]++;
        Ans = max(Ans, 1ll * (tong[a[i]] + cnt[bl[r] - 1][a[i]] - cnt[bl[l]][a[i]]) * c[i]);
    }
    for(int i = l; i <= R[bl[l]]; ++i) tong[a[i]] = 0;
    for(int i = L[bl[r]]; i <= r; ++i) tong[a[i]] = 0;
    return Ans;
}

int main() {
#ifndef ONLINE_JUDGE
freopen("data.in","r",stdin);
#endif
    read(n); read(m);
    for(int i = 1; i <= n; ++i) {
        read(a[i]);
        b[i] = c[i] = a[i];
    }
    sort(b + 1, b + n + 1);
    for(int i = 1; i <= n; ++i) a[i] = lower_bound(b + 1, b + n + 1, a[i]) - b;
    init();
    while(m--) {
        int l, r; read(l); read(r);
        printf("%lld\n", solve(l, r));
    }
}
相关文章
相关标签/搜索