1 条题解
-
0
一、详细思路分析
1. 问题核心:判断区间字符重排后能否构成回文
一个字符串重新排列后能构成回文的核心条件:
- 若区间长度为偶数:所有字符的出现次数必须是偶数(每个字符都能成对出现,对称排列);
- 若区间长度为奇数:恰好有1个字符的出现次数是奇数(作为回文中心),其余均为偶数。 统一结论:区间内出现次数为奇数的字符数量 ≤ 1 时,可构成回文;否则不能。
2. 高效区间查询:前缀和数组
由于方块数量 ( N ) 和查询次数 ( Q ) 均高达 ( 10^5 ),若每次查询都遍历区间统计字符次数,时间复杂度为 ( O(Q*N) ),会超时。因此需要前缀和预处理:
- 定义二维数组 ( s[26][maxn] ),其中 ( s[j][i] ) 表示前 ( i ) 个方块中,第 ( j ) 个字母(( j=0 ) 对应 'A',( j=1 ) 对应 'B',…,( j=25 ) 对应 'Z')的出现次数。
- 预处理时,遍历每个位置 ( i ),对每个字母 ( j ):
- 若当前字符是 ( j ) 对应的字母,则 ( s[j][i] = s[j][i-1] + 1 );
- 否则 ( s[j][i] = s[j][i-1] )(继承前 ( i-1 ) 个的计数)。
- 查询区间 ([L, R]) 时,第 ( j ) 个字母的出现次数 = ( s[j][R] - s[j][L-1] ),时间复杂度 ( O(1) ) 每字母。
3. 整体流程
- 输入处理:读取 ( N, Q ) 和字符字符串;
- 前缀和预处理:构建26个字母的前缀和数组;
- 处理每个查询:
- 读取区间 ( L, R );
- 遍历26个字母,计算区间内每个字母的出现次数,统计奇数次数的字母数量;
- 若奇数次数的字母数 ≤ 1,输出 "YES";否则输出 "NO"。
4. 时间复杂度分析
- 预处理:( O(N26) ),( N=10^5 ) 时,261e5=2.6e6,无压力;
- 查询:( O(Q*26) ),( Q=10^5 ) 时,同样是2.6e6次操作,总时间复杂度 ( O((N+Q)*26) ),完全满足题目要求。
二、带详细注释的代码
#include<iostream> using namespace std; // 定义数组最大长度,适配题目中N≤1e5的限制 const int maxn = 100010; // str存储输入的字符字符串(下标从1开始,方便前缀和计算) char str[maxn]; // s[j][i]:前i个字符中,第j个字母(j=0→A,j=1→B…j=25→Z)的出现次数 int s[26][maxn]; // n:方块数量,m:查询数量(代码中用m代替题目中的Q) int n, m; int main() { // 读取方块数量n和查询数量m cin >> n >> m; // 读取字符串,str+1表示从数组下标1开始存储(避免下标0的前缀和处理麻烦) scanf("%s", str + 1); // 预处理前缀和数组 for(int i = 1; i <= n; i ++) { // 遍历每个字符位置(1~n) for(int j = 0; j < 26; j ++) { // 遍历26个大写字母 // 判断当前位置i的字符是否是第j个字母(j+'A'转换为对应字符) if(str[i] == j + 'A') { // 若是,当前字母计数 = 前i-1个的计数 + 1 s[j][i] = s[j][i - 1] + 1; } else { // 若不是,继承前i-1个的计数 s[j][i] = s[j][i - 1]; } } } // 处理每个查询 while(m --) { int l, r; // 当前查询的区间[L, R] cin >> l >> r; int cnt = 0; // 统计区间内出现次数为奇数的字母数量 // 遍历26个字母,计算每个字母在[l, r]区间的出现次数 for(int i = 0; i < 26; i ++) { // 区间次数 = 前r个的计数 - 前l-1个的计数 int sum = s[i][r] - s[i][l - 1]; // 若次数为奇数,计数+1 if(sum % 2 == 1) cnt ++; } // 判断是否满足回文条件:奇数次数的字母数≤1 if(cnt <= 1) { cout << "YES" << endl; } else { cout << "NO" << endl; } } return 0; }三、代码关键细节补充
- 字符串下标从1开始:前缀和数组 ( s[j][0] ) 默认为0(前0个字符无字母),若字符串从0开始,计算 ( [l, r] ) 时需调整为 ( s[j][r+1] - s[j][l] ),容易出错,因此选择从1开始更直观。
- scanf读取字符串:相比cin,scanf读取字符数组效率更高,适合处理1e5长度的字符串。
- 奇偶性判断:无需关心字母具体出现次数,只需判断奇偶性(因为偶数次可成对,奇数次仅允许1个),因此直接对
sum % 2即可。
四、测试用例验证
以题目输入为例:
7 5 ABAACCA 3 6 → 字符为AACC → 次数:A=2(偶)、C=2(偶)→ cnt=0 → YES 4 4 → 字符为A → 次数:A=1(奇)→ cnt=1 → YES 2 5 → 字符为BAAC → 次数:B=1(奇)、A=2(偶)、C=1(奇)→ cnt=2 → NO 6 7 → 字符为CA → 次数:C=1(奇)、A=1(奇)→ cnt=2 → NO 3 7 → 字符为AACCA → 次数:A=3(奇)、C=2(偶)→ cnt=1 → YES输出与题目一致,验证代码正确性。
- 1
信息
- ID
- 3811
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 5
- 标签
- (无)
- 递交数
- 114
- 已通过
- 41
- 上传者