当前位置: 首页 > news >正文

洛谷 P11965:[GESP202503 七级] 等价消除 ← 位运算(异或) + STL map

【题目来源】
https://www.luogu.com.cn/problem/P11965

【题目描述】
小 A 有一个仅包含小写英文字母的字符串 S。
对于一个字符串,如果能通过每次删去其中两个相同字符的方式,将这个字符串变为空串,那么称这个字符串是可以被等价消除的。
小 A 想知道 S 有多少子串是可以被等价消除的。
一个字符串 S′ 是 S 的子串,当且仅当删去 S 的某个可以为空的前缀和某个可以为空的后缀之后,可以得到 S′。

【输入格式】
第一行,一个正整数 ∣S∣,表示字符串 S 的长度。
第二行,一个仅包含小写英文字母的字符串 S。

【输出格式】
一行,一个整数,表示答案。

【输入样例】
7
aaaaabb

【输出样例】
9

【数据范围】
对于 20% 的测试点,保证 S 中仅包含 a 和 b 两种字符。
对于另外 20% 的测试点,保证 1≤∣S∣≤2000。
对于所有测试点,保证 1≤∣S∣≤
2×10^5。​​​​​​​

【算法分析】
● 异或运算的基本性质
异或运算(XOR)具有以下重要性质:
交换律‌:a ^ b = b ^ a
结合律‌:a ^ (b ^ c) = (a ^ b) ^ c
自反性‌:a ^ a = 0
零元素‌:a ^ 0 = a
可逆性‌:如果 a ^ b = c,那么 a = c ^ b

● 前缀异或和
前缀异或和是一种基于异或运算的前缀和技术,用于高效处理子区间异或相关的问题。
前缀异或和 s 定义为:s[i] = a[1] ^ ... ^ a[i],其中 ^ 表示异或运算。特别地,s[0] = 0。

● 前缀异或和重要性质
求证:若定义前缀异或和 s[i]=a[1]^a[2]^⋯^a[i],则子区间 [le,ri] 的异或和等于
s[ri]^s[le−1]
证明:由前缀异或和的定义,知:s[ri] = a[1]^a[2]^⋯^a[ri],s[le−1] = a[1]^a[2]^⋯^a[le−1]。
又已知 区间 [le,ri] 的异或和等于 a[le]^⋯^a[ri]。
所以 s[ri]^s[le−1] = (a[1]^⋯^a[ri]) ^ (a[1]^⋯^a[le−1])
= (a[1]^⋯^a[le−1]) ^ (a[1]^⋯^a[le−1]^a[le]^⋯^a[ri])
= (a[1]^⋯^a[le−1]) ^ (a[1]^⋯^a[le−1]) ^ (a[le]^⋯^a[ri])
= 0 ^ (a[le]^⋯^a[ri])
= a[le]^⋯^a[ri]
综上,得证。

● 直接统计每个字符的频次,在需要
处理大量子串或动态问题时效率不高。异或方法提供了一种极其高效的‌状态压缩‌技巧。​​​​​​​因为我们不关心每个字符具体出现了多少次,只关心它出现次数的‌奇偶性‌。而异或运算 ^ 的规则正好完美地模拟了奇偶性的变化:
0 ^ 1 = 1(偶 + 奇 = 奇)
1 ^ 1 = 0(奇 + 奇 = 偶)
0 ^ 0 = 0(偶 + 偶 = 偶)
基于存在数学定理“如果一个字符串中每个字符出现次数都是偶数,那么‌必定存在‌一个消除顺序,使得最终能消除为空串”,故在本题中,等价消除的判断方法为“
一个字符串可以被等价消除当且仅当每个字符出现的次数都是偶数‌。​​​​​​​既然是统计字符频次的奇偶性,故可以用异或操作来求解本题。 ​​​​​​​

● 设
preXor[i] 表示字符串 s[0..i-1] 的奇偶状态(用二进制位表示,每位代表一个字母的奇偶性,1 表示奇数次,0 表示偶数次)。那么子串 s[le..ri] 可等价消除 ⇔ preXor[le] == preXor[ri+1]。换句话说,如果 preXor[le] == preXor[ri],那么子串 s[le..ri-1] 可消除。所以问题转化为:在 preXor[0..n] 中,有多少对 (i, j) 满足 i<j 且 preXor[i] == preXor[j],其中 n 为字符串 s 的长度
例如,给定字符串 "
aaaaabb",'a' 记为 1,'b' 记为 2,初始状态 preXor[0] = 0,其计算过程如下:
i=0,字符 'a':state = 0 ^ 1 = 1,preXor[1] = 1。
i=1,字符 'a':state = 1 ^ 1 = 0,preXor[2] = 0。
i=2,字符 'a':state = 0 ^ 1 = 1,preXor[3] = 1。
i=3,字符 'a':state = 1 ^ 1 = 0,preXor[4] = 0。
i=4,字符 'a':state = 0 ^ 1 = 1,preXor[5] = 1。
i=5,字符 'b':state = 1 ^ 2 = 3,preXor[6] = 3。
i=6,字符 'b':state = 3 ^ 2 = 1,preXor[7] = 1。

综上,可得字符串 "aaaaabb" 的 preXor[] 数组值如下表所示。

i01234567
preXor[i]01010131

我们要找 preXor[i] == preXor[j] 且 i < j。观察上表可得,(0,2)(0,4)(2,4)(1,3)(1,5)(1,7)(3,5)(3,7)(5,7)等 9 个“数对”满足要求。它们分别对应着 9 个可等价消除的子串 s[0..1] = "aa"、s[0..3] = "aaaa"、s[2..3] = "aa"、s[1..2] = "aa"、s[1..4] = "aaaa"、s[1..6] = "aaaabb"、s[3..4] = "aa"、s[3..6] = "aabb"、s[5..6] = "bb" 等 9 个可等价消除的子串。

● 代码
x^=1<<(s[i]-'a'); 用位运算(异或和移位)高效地记录字符串中每个字符出现次数的奇偶性‌。本文代码中,利用 x^=1<<(s[i]-'a'); 计算所得的 x 值,就是上文提到的 preXor[] 数组值
(1)s[i] - 'a' 计算当前字符 s[i] 相对于字母 'a' 的偏移量。例如:
'a'-'a'=0,'b'-'a'=1,'c'-'a'=2,……,依此类推。
(2)1<<(s[i]-'a') 将数字 1 左移上面计算的偏移量。例如:
s[i]='a' → 1<<0=1(二进制 0001),
s[i]='b' → 1<<1=2(二进制 0010),
s[i]='c' → 1<<2=4(二进制 0100),……,依次类推。
(3)x ^= ... 将变量 x 与上面计算出的位掩码进行异或操作(0^0=0、0^1=1、1^0=1、1^1=0)。

例如,针对字符串 "abacaba",奇偶状态如下所示(
0 表示偶数,1 表示奇数)。
初始状态:x=0000
遇到 'a':x=0000^0001=0001(a奇)
遇到 'b':x=0001^0010=0011(a奇b奇)
遇到 'a':x=0011^0001=0010(a偶b奇)
遇到 'c':x=0010^0100=0110(a偶b奇c奇)
遇到 'a':x=0110^0001=0111(a奇b奇c奇)
遇到 'b':x=0111^0010=0101(a奇b偶c奇)
遇到 'a':x=0101^0001=0100(a偶b偶c奇)

● 代码
cnt+=mp[x]++; 是统计‌可消除子串数量‌的核心逻辑​​​​​​​。mp[x] 记录的是状态 x 之前出现的次数,每次遇到相同的状态,就意味着找到了‌新的可消除子串‌。这些子串的起点分别是之前所有出现过该状态的位置。所以,当我们在位置 ri 遇到状态 x,且这个状态之前在位置 le 出现过,那么子串 s[le..ri-1] 就是可消除的

【算法代码】

#include<bits/stdc++.h>
using namespace std;typedef long long LL;
map<int,LL> mp;
LL cnt;
string s;
int n,x;int main() {cin>>n>>s;mp[0]=1;for(int i=0; i<n; i++) {x^=1<<(s[i]-'a');cnt+=mp[x]++;}cout<<cnt;return 0;
}/*
in:
7
aaaaabbout:
9
*/





【参考文献】
https://www.luogu.com.cn/problem/solution/P11965
https://blog.csdn.net/hnjzsyjyj/article/details/154517364
https://blog.csdn.net/hnjzsyjyj/article/details/154310120
https://blog.csdn.net/hnjzsyjyj/article/details/154304346





 

http://www.dtcms.com/a/601020.html

相关文章:

  • 智慧团建网登录入口移动网站如何优化排名
  • linux drm子系统专栏介绍
  • termux编译opencv给python用
  • 4.子任务四:Hive 安装配置
  • Lua学习记录(3) --- Lua中的复杂数据类型_table
  • 郑州做定制网站的公司南宁有名的seo费用
  • 华为SRv6技术:引领IP网络进入新时代的智能导航系统
  • 视频汇聚平台EasyCVR:构建通信基站“可视、可管、可控”的智慧安防体系
  • 在云手机中云计算的作用都有哪些?
  • 绿盟防火墙机制
  • 查询数据库上所有表用到图片和视频的数据,并记录到excel表
  • MUVERA:让RAG系统中的多向量检索像单向量一样高效
  • 数据分析笔记02:数值方法
  • 没有网站可以做cpa广告么自己怎么做网站优化
  • Spring Boot实现多数据源连接和切换
  • 【架构设计方法论】概念架构:系统设计的指路明灯
  • 将标签格式为xml的数据集按照8:2的比例划分为训练集和验证集
  • 实战派 JMeter 指南:核心功能、并发压测实操与常见问题解决方案
  • 宁晋网站建设地址信息采集平台
  • 17网站一起做网店如何下单下载站用什么网站系统
  • VMware替代 | ZStack ZSphere虚拟化平台金融级高可用能力解析
  • Go语言编译器源码 | 深入解析Go编译器的设计与实现原理
  • Bootstrap4 文字排版
  • 第13节 93年高能所被入侵,开启中国网络安全发展进程
  • [学习笔记] An Introduction to Flow Matching and Diffusion Models
  • 从零开始的Qt开发指南:(三)信号与槽的概念与使用
  • 视频网站怎么搭建wordpress站点标题图片
  • 加强学校网站建设的要求小说网站建设教程
  • 软考 系统架构设计师历年真题集萃(199)—— 2025年11月系统架构设计师真题2
  • 零门槛部署:在AMD MI300X上极速部署运行GPT-OSS 120B全流程实践