浏览器标题切换
浏览器标题切换end
把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

BZOJ4241: 历史研究

题目地址

题目链接

题解

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

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

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

#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));
	}
}
posted @ 2019-11-07 15:27  henry_y  阅读(105)  评论(0编辑  收藏  举报