SP25180 SUBPAL - Gyanbabas Admission Test
SUBPAL - Gyanbabas Admission Test
题意
给出一个由小写字母组成的字符串 \(s\),求出最长的子串 \(t\) 使得 \(t\) 可以重排成一个回文串。
思路
设回文串中的字符 \(c\) 出现次数为 \(cnt_c\),则显然有 \(\sum (cnt_c \bmod 2) \le 1\),即最多只有一个字符的出现次数为奇数。
看到奇偶很容易想到异或哈希,我们算出 \([1,i]\) 的每个子串的异或哈希值 \(p_i\),则当子串 \([1,i]\) 和子串 \([1,j]\pod{i\le j}\) 哈希值相同时,子串 \([i+1,j]\) 可以重排成回文串,因为 \(p_j\oplus p_i=0\),即子串 \([i+1,j]\) 的每个字符出现次数均为偶数。对于有奇数个字符出现的情况,只需枚举每个字符,出现奇数次的字符自然就会被异或掉。
代码
#include<bits/stdc++.h>
using namespace std;
mt19937 rnd(time(0));
string s;
unordered_map<int,int> vis;
int T,w[128],nw,ans;
signed main(){
cin>>T;
for(int i='a';i<='z';i++) w[i]=rnd();
for(int cc=1;cc<=T;cc++){
vis.clear(),ans=nw=0;
cin>>s;
vis[0]=-1;//记得考虑空串
for(int i=0;i<s.length();i++){
nw^=w[s[i]];
if(!vis.count(nw)) vis[nw]=i;//记录该子串第一次出现的位置
else ans=max(ans,i-vis[nw]);
for(int c='a';c<='z';c++)
if(vis.count(nw^w[c]))
ans=max(ans,i-vis[nw^w[c]]);
}
cout<<"Case "<<cc<<": "<<ans<<endl;
}
return 0;
}

浙公网安备 33010602011771号