[YNOI2017]由乃的商场之旅 莫队

本文介绍了一种利用莫队算法解决特定字符串问题的方法,即计算区间内可重新排序为回文串的子串数量。通过将字符转换为二进制表示,并预处理状态,实现了高效查询。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description
给你一个字符串,每次给一个询问,问这个区间内有多少个子串经过重新排序后可以变成一个回文串。


Sample Input
6 6
zzqzzq
1 6
2 4
3 4
2 3
4 5
1 1


Sample Output
16
4
2
2
3
1


考虑莫队,因为字符只有26个考虑把他压成二进制。
那么你就可以枚举每个位不一样,统计答案。
然后其实状态数是有限的,于是你预处理一下即可。。。


#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
int read() {
	int s = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
	return s * f;
}
struct hh {
	int x, id;
} s[61000];
struct node {
	int l, r, id, bl;
} q[61000]; int m;
int sl[61000], sr[61000];
int sum, ans[61000], S[61000], oo[61000], hg[61000][27];
char ss[61000];

bool cmp(node a, node b) {
	if(a.bl == b.bl) return a.r < b.r;
	return a.bl < b.bl;
}

bool cmp1(hh a, hh b) {return a.x < b.x;}

void jiar(int x) {
	int y = S[x];
	sl[S[x - 1]]++;
	sr[y]++;
	sum += sl[y];
	for(int i = 1; i <= hg[x][0]; i++) sum += sl[hg[x][i]];
}

void jianr(int x) {
	int y = S[x];
	sr[y]--;
	sum -= sl[y];
	for(int i = 1; i <= hg[x][0]; i++) sum -= sl[hg[x][i]];
	sl[S[x - 1]]--;
}

void jial(int x) {
	int y = S[x - 1];
	sl[y]++;
	sr[S[x]]++;
	sum += sr[y];
	for(int i = 1; i <= hg[x - 1][0]; i++) sum += sr[hg[x - 1][i]];
}

void jianl(int x) {
	int y = S[x - 1];
	sl[y]--;
	sum -= sr[y];
	for(int i = 1; i <= hg[x - 1][0]; i++) sum -= sr[hg[x - 1][i]];
	sr[S[x]]--;
}

int main() {
	int n = read(), m = read();
	scanf("%s", ss + 1); int p = sqrt(m);
	for(int i = 1; i <= n; i++) {
		int o = ss[i] - 'a'; s[i].id = i;
		s[i].x = s[i - 1].x ^ (1 << o);
	} s[n + 1].x = 0; s[n + 1].id = 0;
	sort(s + 1, s + n + 2, cmp1);
	int tp = 0;
	for(int i = 1; i <= n + 1; i++) {
		if(s[i].x != s[i - 1].x || i == 1) tp++;
		S[s[i].id] = tp; oo[tp] = s[i].x;
	}
	for(int i = 0; i <= n; i++) {
		int hh = oo[S[i]];
		for(int j = 0; j < 26; j++) {
			int yy = hh ^ (1 << j);
			int l = 1, r = n + 1, ans;
			while(l <= r) {
				int mid = (l + r) / 2;
				if(s[mid].x <= yy) l = mid + 1, ans = mid;
				else r = mid - 1;
			} if(s[ans].x == yy) hg[i][++hg[i][0]] = S[s[ans].id];
		}
	}
	for(int i = 1; i <= m; i++) {
		q[i].l = read(), q[i].r = read(), q[i].id = i;
		q[i].bl = (q[i].l - 1) / p + 1;
	} sort(q + 1, q + m + 1, cmp);
	int ll = 1, rr = 0; sum = 0;
	for(int i = 1; i <= m; i++) {
		for(int j = rr + 1; j <= q[i].r; j++) jiar(j);
		for(int j = rr; j > q[i].r; j--) jianr(j);
		for(int j = ll; j < q[i].l; j++) jianl(j);
		for(int j = ll - 1; j >= q[i].l; j--) jial(j);
		ll = q[i].l, rr = q[i].r;
		ans[q[i].id] = sum;
	} for(int i = 1; i <= m; i++) printf("%d\n", ans[i]);
	return 0;
}
### 关于 YNOI2019 排问题的分析 YNOI(Yet Another National Olympiad in Informatics)是一类针对信息学竞赛选手的经典算法比赛。对于 YNOI2019 中涉及的排问题,通常会涉及到动态规划、贪心算法或者高级数据结构的应用。 #### 动态规划方法 如果该问题是关于排列组合或最优策略的选择,则可以考虑使用动态规划的方法来解决。假设我们需要找到一种最优的方式使得伍满足某些条件下的最小代价或最大收益。可以通过定义状态 `dp[i][j]` 来表示前 i 个人按照某种顺序排列时的状态 j 下的最佳结果[^1]。转移方程的设计取决于具体的约束条件和目标函数。 #### 贪心算法应用 当题目允许局部最优解能够推导出全局最优解的情况下,采用贪心策略可能是更高效的做法。例如,在安排人员进入列的过程中,每次都尝试将当前最适合的人加入到尾或其他位置,从而逐步构建最终序列[^2]。 #### 高级数据结构支持 有些复杂的排场景下需要用到平衡树、线段树甚至是并查集这样的高级数据结构来进行维护和查询操作。比如在线处理大量询问的同时保持快速更新的能力就非常依赖这些工具的支持[^3]。 以下是利用 Python 实现的一个简单示例代码片段展示如何通过模拟过程完成基本功能: ```python def solve_queue_problem(people): people.sort(key=lambda x: (x[0], -x[1])) # 假设按身高降序排序 result = [] for p in people: pos, h = p result.insert(pos, h) return result # 测试用例 test_input = [[0,7],[1,7],[1,6],[2,5],[3,5]] print(solve_queue_problem(test_input)) ``` 此代码仅为示意性质,并未完全覆盖所有可能情况,请根据实际需求调整逻辑细节。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值