bzoj2724 [Violet 6]蒲公英

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2724

【题解】

比较经典的区间求众数问题。

我们考虑分块,ans[i,j]表示第i个块到第j个块答案是多少,这个可以预处理。

然后离散值,对于每个值存一个vector,里面存的是出现这个值的所有下标。

可以证明,答案只会在整块的答案和两端部分的所有数中选择,那么提取这些数,排序。

可以在vector中二分出出现的位置。就能求有多少个了,然后比较即可。

复杂度O(n根号nlogn)

# include <vector>
# include <stdio.h>
# include <string.h>
# include <algorithm>
// # include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int M = 4e4 + 10, N = 310, BLOCK = 200;
const int mod = 1e9+7;

# define RG register
# define ST static

int n, m, a[M], bl[M], B, q;
int ans[N][N];
int bst[N], bnd[N];
vector<int> ps, tt, g[M];
int t[M], mx, mxid, lst;

inline void prepare(int x) {
    int tem = x;
    mx = 0; mxid = 2333333;
    for (int i=(x-1)*BLOCK+1; i<=n; ++i) {
        t[a[i]] ++;
        if(t[a[i]] > mx) {
            mx = t[a[i]];
            mxid = a[i];
        } else if(t[a[i]] == mx) {
            if(a[i] < mxid) mxid = a[i];
        }
        if(i == bnd[tem]) {
            ans[x][tem] = mxid;
            ++tem;
        }
    }
    for (int i=(x-1)*BLOCK+1; i<=n; ++i) --t[a[i]];
}

int main() {
    scanf("%d%d", &n, &q); 
    for (int i=1; i<=n; ++i) {
        scanf("%d", &a[i]);
        ps.push_back(a[i]);
    }
    sort(ps.begin(), ps.end());
    ps.erase(unique(ps.begin(), ps.end()), ps.end());
    for (int i=1; i<=n; ++i) {
        a[i] = lower_bound(ps.begin(), ps.end(), a[i]) - ps.begin() + 1;
//        printf("%d ", a[i]);
        g[a[i]].push_back(i);
    }
//    puts("
================");
    m = ps.size();
//    for (int i=1; i<=m; ++i) {
//        printf("==size = %d
", g[i].size());
//        for (int j=0; j<g[i].size(); ++j) printf("%d ", g[i][j]);
//        puts("");
//    }
    for (int i=1; i<=n; ++i) bl[i] = (i-1)/BLOCK+1;
    B = bl[n]; 
    for (int i=1; i<=B; ++i) bst[i] = (i-1)*BLOCK+1, bnd[i] = min(n, i*BLOCK);
    for (int i=1; i<=B; ++i) prepare(i);
    lst = 0;
    while(q--) {
        int l, r; scanf("%d%d", &l, &r);
        l = (l+lst-1+n)%n+1;
        r = (r+lst-1+n)%n+1;
        if(l > r) swap(l, r);
        if(bl[l] == bl[r]) {
            mx = 0, mxid = 2333333;
            for (int i=l; i<=r; ++i) {
                t[a[i]] ++;
                if(t[a[i]] > mx) {
                    mx = t[a[i]];
                    mxid = a[i];
                } else if(t[a[i]] == mx) {
                    if(a[i] < mxid) mxid = a[i];
                }
            }
            for (int i=l; i<=r; ++i) --t[a[i]]; 
            printf("%d
", lst = ps[mxid-1]);
        } else {
            tt.clear();
            if(bl[l] + 1 != bl[r]) tt.push_back(ans[bl[l]+1][bl[r]-1]);    
            for (int i=l; i<=bnd[bl[l]]; ++i) tt.push_back(a[i]);
            for (int i=bst[bl[r]]; i<=r; ++i) tt.push_back(a[i]);
            sort(tt.begin(), tt.end());
            tt.erase(unique(tt.begin(), tt.end()), tt.end()); 
//            for (int i=0, sz=tt.size(); i<sz; ++i) printf("%d ", tt[i]);
//            puts("
======");
            mx = 0, mxid = 2333333;
            for (int i=0, sz=tt.size(); i<sz; ++i) {
                int x = tt[i];
                int xi = upper_bound(g[x].begin(), g[x].end(), r)-g[x].begin(), xj = lower_bound(g[x].begin(), g[x].end(), l)-g[x].begin()+1; 
//                printf("l = %d, r = %d
", xj, xi);
                int times = upper_bound(g[x].begin(), g[x].end(), r)-lower_bound(g[x].begin(), g[x].end(), l);
//                printf("x=%d, times=%d
", tt[i], times);
                if(times > mx) mx = times, mxid = x;
            }
            printf("%d
", lst = ps[mxid-1]);
        }
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/galaxies/p/bzoj2724.html