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));
    }
}
相關文章
相關標籤/搜索