P4135 作诗

分块经典题。

这种题显然是数据结构,1n1051 \leq n \leq 10^5,考虑根号复杂度做法。于是考虑使用分块。

我们先预处理出两个值:resi,j,cnti,jres_{i, j}, cnt_{i, j}resi,jres_{i,j} 表示第 ii 块到第 jj 块的答案,cnti,jcnt_{i, j} 表示从第 11 块到第 ii 块中 jj 出现的次数。

那么若要求第 ll 块到第 rr 块中 xx 出现的次数,保证 lrl \leq r,就是 cntr,xcntl1,xcnt_{r, x} - cnt_{l - 1, x}。查询同块暴力,不同块的时候先求整块,然后对零散块求出与整块的答案的差即可。

复杂度 O(nn)O(n \sqrt{n})

代码:

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

const int N = 1e5 + 5, M = 325;

int n, m, c;
int a[N], ans = 0, l, r;

int bel[N], block;

int mph[N];
bool vis[N];

int g[M][N], res[M][M];

#define L(x) ((x - 1) * block)

#define get(l, r, x) (l > r ? 0 : g[r][x] - g[l - 1][x])

int main()
{
	scanf("%d%d%d", &n, &c, &m);
	block = sqrt(n);
	for (int i = 1; i <= n; i++) scanf("%d", &a[i]), bel[i] = i / block + 1;
	for (int i = 1; i <= bel[n]; i++)
	{
		for (int j = 0; j <= c; j++) g[i][j] = g[i - 1][j];
		int l = L(i), r = L(i + 1) - 1;
		for (int j = l; j <= r; j++) g[i][a[j]]++;
	}
	for (int i = 1; i <= bel[n]; i++)
	{
		for (int j = i; j <= bel[n]; j++)
		{
			res[i][j] = res[i][j - 1];
			int l = L(j), r = L(j + 1) - 1;
			for (int k = l; k <= r; k++)
			{
				if (vis[a[k]]) continue;
				int pre = get(i, j - 1, a[k]), now = get(j, j, a[k]);
				if (pre == 0)
				{
					if (!(now & 1)) res[i][j]++;
				}
				else if (pre % 2 != (pre + now) % 2)
				{
					if (pre % 2) res[i][j]++;
					else res[i][j]--;
				}
				vis[a[k]] = true;
			}
			for (int k = l; k <= r; k++) vis[a[k]] = false;
		}
	}
	while (m--)
	{
		int l, r;
		scanf("%d%d", &l, &r);
		l = (l + ans) % n + 1, r = (r + ans) % n + 1;
		if (l > r) swap(l, r);
		ans = 0;
		if (bel[l] == bel[r])
		{
			for (int i = l; i <= r; i++)
			{
				mph[a[i]]++;
			}
			for (int i = l; i <= r; i++)
			{
				int x = mph[a[i]];
				if (x > 0 && x % 2 == 0) ans++;
				mph[a[i]] = 0;
			}
		}
		else
		{
			int nl = bel[l] + 1, nr = bel[r] - 1;
			int rl = L(bel[l] + 1) - 1, lr = L(bel[r]);
			ans = res[nl][nr];
			for (int i = l; i <= rl; i++) mph[a[i]]++;
			for (int i = lr; i <= r; i++) mph[a[i]]++;
			for (int i = l; i <= rl; i++)
			{
				if (vis[a[i]]) continue;
				int pre = get(nl, nr, a[i]), now = mph[a[i]];
				if (pre == 0)
				{
					if (!(now & 1)) ans++;
				}
				else if (pre % 2 != (pre + now) % 2)
				{
					if (pre & 1) ans++;
					else ans--;
				}
				vis[a[i]] = true;
				mph[a[i]] = 0;
			}
			for (int i = lr; i <= r; i++)
			{
				if (vis[a[i]]) continue;
				int pre = get(nl, nr, a[i]), now = mph[a[i]];
				if (pre == 0)
				{
					if (!(now & 1)) ans++;
				}
				else if (pre % 2 != (pre + now) % 2)
				{
					if (pre & 1) ans++;
					else ans--;
				}
				vis[a[i]] = true;
				mph[a[i]] = 0;
			}
			for (int i = l; i <= rl; i++) vis[a[i]] = false;
			for (int i = lr; i <= r; i++) vis[a[i]] = false;
		}
		printf("%d\n", ans);
	}
	return 0;
}
posted @   HappyBobb  阅读(4)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示