题解:P11190 「KDOI-10」反回文串

Link\text{Link}

题意

将一个长度为 nn 的字符串 ss 划分为最多的子序列,使 ss 每个位置的字符恰好属于一个子序列且每个子序列中的字符按顺序组成的串不为回文串。要求判断有无解,若有解,给出最多的子序列个数 kk 和一种方案。

分析

单个字符肯定是回文串,所以非回文串至少要两个不同的字符,kk 的上界为 n2\left\lfloor\frac{n}{2}\right\rfloor

先判掉一个显然无解的情况:字符全相同。剩下的就至少有两种字符,我们考虑能否将 kk 取到上界。

  • 若出现次数最多的字符的数量不超过 n2\left\lfloor\frac{n}{2}\right\rfloor,显然我们可以找到 n2\left\lfloor\frac{n}{2}\right\rfloor 对不同的字符,每次贪心地取出现次数最多的两个字符即可,可用堆维护。若最后还剩下一个,我们暴力看它能插入到哪个子序列中,能插就插。
  • 若出现次数最多的字符的数量超过 n2\left\lfloor\frac{n}{2}\right\rfloor,不妨记这个字符为 uu,出现次数为 cntucnt_u,此时答案上界为 ncntun-cnt_u。此时也可分两种情况讨论:
    • nn 为偶数,我们可以这样构造:把每个非 uu 字符与位置最前的未配对过的 uu 配对,把最后剩下的 uu 全扔到最后一个子序列中,由于每个子序列的长度均为偶数,所以一定不存在回文串。
    • nn 为奇数,我们把 n3n\le 3 的情况特判一下,否则,考虑多出来的一个怎么分配。考虑第一个非 uu 字符,我们尝试给他分配 22uu,若有两个 uu 在它前面,就分配这两个,否则必然存在两个 uu 在它后面,匹配后面两个,这样它一定不会构成回文串。对于剩下的字符,按偶数的情况匹配即可。但是,这样会有一个特殊情况 uuuvuuu\texttt{uuuvuuu} 怎么分配都会存在回文串,直接判无解即可。

代码

代码很丑。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
long long read(){
	long long x=0,f=1;char ch=getchar();
	while(!isdigit(ch))
	{if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
void write(long long x){
    if(x<0) putchar('-'),x=-x;
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
const int N=1e5+10;
int C,T,n,tot;
char s[N];
int cnt[27];
vector<int>chs[27];
vector<int>fan[N],e;
int id[N];
void printok(){
	puts("Huoyu");
	printf("%d\n",tot);
	for(int i=1;i<=tot;i++){
		printf("%d ",fan[i].size());
		for(auto x:fan[i]){
			printf("%d ",x);
		}
		puts("");
	}
}
bool cmp(int x,int y){
	return cnt[x]>cnt[y];
}
struct Node{
	int x;
	bool operator<(const Node u)const{
		return chs[x].size()<chs[u.x].size();
	}
};
priority_queue<Node>q;
void work1(){
	int cant=0;
	while(q.size())q.pop();
	for(int i=0;i<26;i++){
		if(chs[i].size()){
			q.push((Node){i});
		}
	}
	while(1){
		if(!q.size()){
			break;
		}
		int i=q.top().x;
		q.pop();
		if(!chs[i].size())break;
		if(!q.size()){
			cant=chs[i].back();
			break;
		}
		int j=q.top().x;q.pop();
		if(!chs[j].size()){
			cant=chs[i].back();
			break;
		}
		int x=chs[i].back(),y=chs[j].back();
		tot++;
		if(x>y)swap(x,y);
		fan[tot].push_back(x);
		fan[tot].push_back(y);
		chs[i].pop_back();chs[j].pop_back();
		if(chs[i].size())q.push((Node){i});
		if(chs[j].size())q.push((Node){j});
	}
	if(n&1){
		for(int i=1;i<=tot;i++){
			e=fan[i];
			e.push_back(cant);
			sort(e.begin(),e.end());
			if(s[e[0]]==s[e[2]])continue;
			fan[i]=e;break;
		}
	}
	printok();
}
void work2(int u){
	int tu=0;
	if(n&1){
		int t=0;
		for(int i=1;i<=n;i++){
			if(s[i]-'a'!=u){
				t=i;break;
			}
		}
		if(chs[u].size()==n-1){
			if(t==n/2+1){
				puts("Shuiniao");
			}
			else{
				tot=1;
				for(int i=1;i<=n;i++){
					fan[1].push_back(i);
				}
				printok();
			}
			return;
		}
		int l=0,r=chs[u].size()-1;
		if(t>2){
			tot=1;
			fan[1].push_back(1);
			fan[1].push_back(2);
			fan[1].push_back(t);
			tu=2;
			for(int i=0;i<26;i++){
				if(i==u)continue;
				while(chs[i].size()){
					int x=chs[i].back();
					chs[i].pop_back();
					if(x==t)continue;
					int y=chs[u][tu++];
					if(x>y)swap(x,y);
					tot++;
					fan[tot].push_back(x);
					fan[tot].push_back(y);
				}
			}
			for(;tu<chs[u].size();tu++){
				fan[tot].push_back(chs[u][tu]);
			}
			sort(fan[tot].begin(),fan[tot].end());
			//printf("case 2.1\n");
			printok();
		}
		else{
			tot=1;
			fan[1].push_back(t);
			fan[1].push_back(chs[u][r-1]);
			fan[1].push_back(chs[u][r]);
			r--;
			for(int i=0;i<26;i++){
				if(i==u)continue;
				while(chs[i].size()){
					int x=chs[i].back();
					chs[i].pop_back();
					if(x==t)continue;
					int y=chs[u][tu++];
					if(x>y)swap(x,y);
					tot++;
					fan[tot].push_back(x);
					fan[tot].push_back(y);
				}
			}
			for(;tu<r;tu++){
				fan[tot].push_back(chs[u][tu]);
			}
			sort(fan[tot].begin(),fan[tot].end());
			//printf("case 2.2\n");
			printok();
		}
	}
	else{
		for(int i=0;i<26;i++){
			if(i==u)continue;
			while(chs[i].size()){
				int x=chs[i].back();
				chs[i].pop_back();
				int y=chs[u][tu++];
				if(x>y)swap(x,y);
				tot++;
				fan[tot].push_back(x);
				fan[tot].push_back(y);
			}
		}
		for(;tu<chs[u].size();tu++){
			fan[tot].push_back(chs[u][tu]);
		}
		sort(fan[tot].begin(),fan[tot].end());
		//printf("case 1\n");
		printok();
	}
}
void solve(){
	bool flag=1;
	for(int i=2;i<=n;i++){
		if(s[i]!=s[i-1])flag=0;
	}
	if(flag){
		puts("Shuiniao");
		return;
	}
	if(n==2){
		puts("Huoyu");
		printf("1\n2 1 2\n");
		return;
	}
	if(n==3){
		if(s[1]==s[3]){
			puts("Shuiniao");
			return;
		}
		puts("Huoyu");
		printf("1\n3 1 2 3\n");
		return;
	}
	memset(cnt,0,sizeof(cnt));
	for(int i=0;i<26;i++)chs[i].clear();
	for(int i=1;i<=n;i++){
		cnt[s[i]-'a']++;
		chs[s[i]-'a'].push_back(i);
		fan[i].clear();
	}
	int mx=0,pos=0;
	tot=0;
	for(int i=0;i<26;i++){
		if(cnt[i]>mx){
			mx=cnt[i],pos=i;
		}
	}
	if(mx<=n/2){
		work1();
	}
	else work2(pos);
}
int main(){
	//freopen("anti2.in","r",stdin);
	//freopen("anti.out","w",stdout);
	C=read();T=read();
	int t1=0;
	while(T--){
		t1++;
		n=read();
		scanf("%s",s+1);
		/*if(t1!=4){
			continue;
		}*/
		solve();
	}
	return 0;
}
posted @ 2024-10-14 10:42  luckydrawbox  阅读(13)  评论(0)    收藏  举报  来源