「AtCoder 1219」歴史の研究

给出 n 个整数 \(x_1, x_2, ...,x_n\) ,询问 [l, r] 中 \(max\{x_k\times cnt_{x_k}\}\) ( \(cnt_i\) 表示 i 出现的次数)

Luogu

AtCoder

分析

回滚莫队裸题。

当然也可以用分块做,但我一开始打的分块,成功的只过了 4 个点......没调出来......

顺便贴一下官方题解,虽然是日文

歴史の研究

代码

回滚莫队

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 100005
#define il inline
#define re register
#define DEBUG puts("ok")
#define tie0 cin.tie(0),cout.tie(0)
#define fastio ios::sync_with_stdio(false)
#define File(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout)
using namespace std;
typedef long long ll;

template <typename T> inline void read(T &x) {
	T f = 1; x = 0; char c;
    for (c = getchar(); !isdigit(c); c = getchar()) if (c == '-') f = -1;
    for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
    x *= f;
}

int n, m, q, sz;
int bl[N], L[N], R[N], id[N], cnt[N], tot[N];
ll t[N], hs[N], ans[N];

struct query {
	int l, r, id;
	friend bool operator < (query x, query y) {
		return (bl[x.l] ^ bl[y.l]) ? bl[x.l] < bl[y.l] : x.r < y.r;
	}
} qy[N];

int main() {
	read(n), read(q);
	sz = sqrt(n);
	for (int i = 1; i <= n; ++i) {
		read(t[i]), hs[i] = t[i];
		bl[i] = (i - 1) / sz + 1;
	}
	m = bl[n];
	for (int i = 1; i <= m; ++i) {
		L[i] = (i - 1) * sz + 1;
		R[i] = i * sz;
	}
	sort(hs + 1, hs + 1 + n);
	int num = unique(hs + 1, hs + 1 + n) - hs - 1;
	for (int i = 1; i <= n; ++i)
		id[i] = lower_bound(hs + 1, hs + 1 + num, t[i]) - hs;
	for (int i = 1; i <= q; ++i) {
		read(qy[i].l), read(qy[i].r);
		qy[i].id = i;
	}
	sort(qy + 1, qy + 1 + q);
	int i = 1;
	for (int k = 0; k <= m; ++k) {
		int l = R[k] + 1, r = R[k];
		ll now = 0;
		memset(cnt, 0, sizeof cnt);
		for ( ; bl[qy[i].l] == k; ++i) {
			int ql = qy[i].l, qr =qy[i].r;
			ll tmp = 0;
			if (bl[ql] == bl[qr]) {
				for (int j = ql; j <= qr; ++j) tot[id[j]] = 0;
				for (int j = ql; j <= qr; ++j) {
					++tot[id[j]];
					tmp = max(tmp, 1ll * tot[id[j]] * t[j]);
				}
				ans[qy[i].id] = tmp;
			}
			else {
				while (r < qr) {
					++cnt[id[++r]];
					now = max(now, 1ll * cnt[id[r]] * t[r]);
				}
				tmp = now;
				while (l > ql) {
					++cnt[id[--l]];
					now = max(now, 1ll * cnt[id[l]] * t[l]);
				}
				ans[qy[i].id] = now;
				while (l < R[k] + 1) --cnt[id[l++]];
				now = tmp;
			}
		}
	}
	for (int i = 1; i <= q; ++i) printf("%lld\n", ans[i]);
	return 0;
}

官方正解

#include<stdio.h>
#include<vector>
#include<algorithm>
#define SQ 100
/*

bucket size: 100

*/
using namespace std;
int c[110000];
int d[110000];
int z[110000];
vector<int>v[110000];
long long e[110000];
long long f[3000][3000];
int main(){
	int a,b;
	scanf("%d%d",&a,&b);
	for(int i=0;i<a;i++)scanf("%d",c+i);
	for(int i=0;i<a;i++){
		z[i]=c[i];
	}
	std::sort(z,z+a);
	for(int i=0;i<a;i++){
		d[i]=lower_bound(z,z+a,c[i])-z;
		v[d[i]].push_back(i);
	}
	for(int i=0;i<a/SQ;i++){
		for(int j=0;j<a;j++)e[j]=0LL;
		long long val=0LL;
		for(int j=i*SQ;j<=a;j++){
			if(j%SQ==0){
				f[i][j/SQ]=val;
			}
			e[d[j]]+=z[d[j]];
			val=max(val,e[d[j]]);
		}
	}
	for(int i=0;i<b;i++){
		int p,q;
		scanf("%d%d",&p,&q);
		p--;
		long long ret=f[(p+SQ-1)/SQ][q/SQ];
		for(int j=p;j%SQ;j++){
			ret=max(ret,(long long)z[d[j]]*(lower_bound(v[d[j]].begin(),v[d[j]].end(),q)-lower_bound(v[d[j]].begin(),v[d[j]].end(),p)));
		}
		for(int j=q-1;(j+1)%SQ;j--){
			ret=max(ret,(long long)z[d[j]]*(lower_bound(v[d[j]].begin(),v[d[j]].end(),q)-lower_bound(v[d[j]].begin(),v[d[j]].end(),p)));
		}
		printf("%lld\n",ret);
	}
}

我的错误分块代码

Code

posted @ 2020-01-17 21:39  小蒟蒻hlw  阅读(159)  评论(0)    收藏  举报