Beer Mugs(异或和前缀+最长回文)

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述题意:给你一个长度为n的字符串,求一个连续最长的一个区间,这个区间里面的字符可以任意顺序排列,最终使得这个区间形成一个回文;那么求这个区间的最长长度;
这个题我也是看了题解才看明白的;
比如我们举个例对于这种字符串:aabb那么如果我把a看成001,b看成010是不是用异或前缀和是不是就能发现如果是偶数个相同字符那么异或为0,所以aabb那么就可以有aa,bb,aabb,这里我是说明一点就是偶数个相同字符那么就能保证异或和为0;
但是如果是奇数呢?怎么判断,也就是上面的aab其实也可以组合为回文,但是怎么搞定这种情况呢?
我是不是可以在扫描到b的时候在增加一个b呢?这样是不是我就能够把他给异或回去了?
所以整体思路就是:求异或前缀和,用一个map记录每次不同的异或和出现的第一次的坐标;
之后就可以搞定了;读者可以边读代码边手动模拟,这个题挺考思维的;不过不是map默认值为0吗?为什么我还需要mp[0]=0呢?我就觉得很奇怪。。。。。。。。。。不写mp[0]=0那么就过不了。。。。。。。
AC代码:

#include<bits/stdc++.h>
using namespace std;
char s[300050];
unordered_map<int,int> mp;
int ans;
int main(){
    
    
	int n;
	scanf("%d %s",&n,&s);
	int t=0;
	mp[0]=0;
	for(int i=0;i<n;i++){
    
    
		  t^=1<<(s[i]-'a');
		  if(!mp.count(t)) mp[t]=i+1;//记录第一次出现的坐标 
		  else  ans=max(ans,i+1-mp[t]); //答案
		  //对于1个字符的,那么我相应补上一个字符,就可以求出长度了  比如aba那么我扫描到最后一个a的时候,那么我补上一个b
		  for(int j=0;j<20;j++){
    
    
		  	  if(mp.count(t^(1<<j))){
    
    //补一个字符上去,如果前面还出现过,说明这一段可以作为回文 
		  	  	   ans=max(ans,i+1-mp[t^(1<<j)]);
				}
		  } 
	}
      printf("%d\n",ans);
	 return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_44555205/article/details/104504248