题解:CF1951E(No Palindromes)

题解:CF1951E(No Palindromes)

题目翻译:给定一个长度为 n n n 的字符串 s s s,询问是否可以将其分成若干份,使得每一份都不是 回文串。若可以,输出 YES 并给出任意 一组方案;若不可以,则直接输出 NO。其中,数据多测,共 t t t 组,保证 ∑ n ≤ 1 0 6 \sum n\leq10^6 ∑n≤106。

先观察数据范围1e6 级别,基本上就是 O ( n ) O(n) O(n) 的,看来是一道结论题

为了之后表述方便,我们不妨将字符串分成若干个部分 ,使得每个部分 中的字符都相同相邻两个部分 的字符不相等 。记这样的部分数为 c n t cnt cnt,记第 i i i 个部分为 x i x_i xi。

于是,我们开始分情况讨论:

  • 当 c n t cnt cnt 为偶数 时,不难证明,整个字符串 一定不是 一个回文串 ,因此可以 分,整体分成一份即可。当然,我们将它的奇数段和偶数段两两搭配分在一起也是可以的。
  • 当 c n t = 1 cnt=1 cnt=1 时,显然无论怎么分,每一段内的字母都一定相同,因此不可以分。
  • 当 c n t cnt cnt 为奇数 ( 1 1 1 除外)时,我们要想能分成,要么将奇数 个段(显然 1 1 1 除外)分在一起,要么将某一段拆开,还需要继续分类:
    • 当存在 1 ≤ i ≤ c n t − 2 1\leq i\leq cnt-2 1≤i≤cnt−2,使得 x i = x i + 2 x_i=x_{i+2} xi=xi+2 时,那一定可以 分(就是用第 i d id id、 i d + 1 id+1 id+1 和 i d + 2 id+2 id+2 段组成前面所说的"奇数 个段"),但是怎么分还要分类(记我们找到的其中任意 一个 i i i 为 i d id id):
      • 当 i d id id 为偶数 时,在第 i d id id 段之前 有偶数个段,我们将其奇数段和偶数段两两搭配 ;对于中间,我们将第 i d id id、 i d + 1 id+1 id+1 和 i d + 2 id+2 id+2 段分在一起;对于第 i d + 2 id+2 id+2 之后 也有偶数个段,我也是时将其奇数段和偶数段两两搭配
      • 当 i d id id 为奇数 时,在第 i d − 1 id-1 id−1 段之前 有偶数个段,我们将其奇数段和偶数段两两搭配 ;对于中间,我们将第 i d − 1 id-1 id−1、 i d id id、 i d + 1 id+1 id+1、 i d + 2 id+2 id+2 和 i d + 3 id+3 id+3 段分在一起;对于第 i d + 3 id+3 id+3 之后 也有偶数个段,我也是时将其奇数段和偶数段两两搭配
    • 当不存在 1 ≤ i ≤ c n t − 2 1\leq i\leq cnt-2 1≤i≤cnt−2,使得 x i = x i + 2 x_i=x_{i+2} xi=xi+2 时,给定字符串一定是由两种段交替组成的,我们需要继续分类(记其中第奇数 段的字符数量为 u u u,第偶数 段的字符数量为 v v v):
      • 当 u = v = 1 u=v=1 u=v=1 时,由于总段数 c n t cnt cnt 为奇数 ,而任何一段都不可能拆成两半 ,因此最终的字符串一定被分成两份,分别有奇数 个段和偶数 个段组成,显然那个由奇数 个段组成的一部分一定是回文串 ,因此不可以分。
      • 当 v ≠ 1 v\neq 1 v=1 时,第 2 2 2 段可以被拆成两半,因此可以 分,将其第一个字符 与前面的第 1 1 1 段分成一部分,第 2 2 2 段的剩余的部分 与它右侧所有剩余字符分成另一部分。
      • 当 v = 1 v=1 v=1 且 u ≠ 1 u\neq 1 u=1 时,再分情况:
        • 当 c n t = 3 cnt=3 cnt=3 时,只有第 1 1 1 段和第 3 3 3 段可以拆开,此时一定有一部分中所有字符相同,因此不能分。
        • 当 c n t > 3 cnt>3 cnt>3 时,将第 3 3 3 部分拆成两半,就可以 分,分法与上面的"当 v ≠ 1 v\neq 1 v=1 时"类似,这里不再赘述。

于是,我们通过一大片子的分类讨论解决了这道题。

还是给个代码吧!

cpp 复制代码
#include<bits/stdc++.h>
#define N 1100000
#define fors(i,b,e) for(int i=b;i<=e;i++)
#define fst first
#define scd second
#define pb push_back
using namespace std;
int t;
char s[N];
int n;
pair<char,int>x[N];
bool operator==(pair<char,int>x,pair<char,int>y);
int main(){
	scanf("%d",&t);
	while(t--){
		scanf("%s",s+1);
		n=strlen(s+1);
		int cnt=0;
		fors(i,1,n){
			if(i==1||s[i]!=s[i-1])cnt++,x[cnt]={s[i],1};
			else x[cnt].scd++;
		}
		if(cnt%2==0)printf("YES\n1\n%s\n",s+1);
		else if(cnt==1)printf("NO\n");
		else{
			int id=0;
			fors(i,1,cnt-2)if(x[i]!=x[i+2]){
				id=i;
				break;
			}
			if(id!=0){
				if(id%2==1){
					printf("YES\n%d\n",cnt/2);
					for(int i=1;i+1<id;i+=2){
						fors(j,1,x[i+0].scd)printf("%c",x[i+0].fst);
						fors(j,1,x[i+1].scd)printf("%c",x[i+1].fst);
						printf(" ");
					}
					fors(i,0,2)fors(j,1,x[id+i].scd)printf("%c",x[id+i].fst);
					printf(" ");
					for(int i=id+3;i+1<=cnt;i+=2){
						fors(j,1,x[i+0].scd)printf("%c",x[i+0].fst);
						fors(j,1,x[i+1].scd)printf("%c",x[i+1].fst);
						printf(" ");
					}
					printf("\n");
				}else{
					printf("YES\n%d\n",cnt/2-1);
					for(int i=1;i+1<id-1;i+=2){
						fors(j,1,x[i+0].scd)printf("%c",x[i+0].fst);
						fors(j,1,x[i+1].scd)printf("%c",x[i+1].fst);
						printf(" ");
					}
					fors(i,-1,3)fors(j,1,x[id+i].scd)printf("%c",x[id+i].fst);
					printf(" ");
					for(int i=id+4;i+1<=cnt;i+=2){
						fors(j,1,x[i+0].scd)printf("%c",x[i+0].fst);
						fors(j,1,x[i+1].scd)printf("%c",x[i+1].fst);
						printf(" ");
					}
					printf("\n");
				}
			}else{
				int u=x[1].scd,v=x[2].scd;
				if(u==1&&v==1)printf("NO\n");
				else if(v!=1){
					printf("YES\n2\n");
					fors(i,1,u)printf("%c",x[1].fst);
					printf("%c ",x[2].fst);
					fors(i,2,v)printf("%c",x[2].fst);
					fors(i,3,cnt)fors(j,1,x[i].scd)printf("%c",x[i].fst);
					printf("\n");
				}else{
					if(cnt==3)printf("NO\n");
					else{
						printf("YES\n2\n");
						fors(i,1,u)printf("%c",x[1].fst);
						fors(i,1,v)printf("%c",x[2].fst);
						printf("%c ",x[3].fst);
						fors(i,2,u)printf("%c",x[3].fst);
						fors(i,4,cnt)fors(j,1,x[i].scd)printf("%c",x[i].fst);
						printf("\n");
					}
				}
			}
		}
	}
	return 0;
}
bool operator==(pair<char,int>x,pair<char,int>y){
	return x.fst==y.fst&&x.scd==y.scd;
}

注意

如果你信心满满地写了一个自以为十分正确的代码提交上去却 Wrong answer on test 2,请不要恼火,慢慢核对,看看有没有哪里写错了,相信你能调对!

相关推荐
_Twink1e6 小时前
openJiuwen 实训营 Day 1 · WorkSwarm 入门教程
开发语言·c++·openjiuwen
dong_junshuai7 小时前
每天一个开源项目#87 fmt:24.5K Stars 的 C++ 格式化核心
c++·开源·github
雪的季节8 小时前
Multisim14.0的详细中文安装步骤【附安装包】
c++
Persistent的粽子!9 小时前
C++:类与对象(二)
开发语言·c++
蒸蒸yyyyzwd9 小时前
cpp 选手备战秋招学习笔记 day23
c++·求职招聘
.YM.Z9 小时前
C++ STL 容器深度剖析:vector 与 list 的模拟实现及对比
开发语言·c++·vector·list
mengzhi啊11 小时前
QEventLoop loop配合loop.exec();替代while(1)。电脑cpu占用为0,使用while(1)cpu占用率100%
c++·qt
HugoStudio_SWAN11 小时前
洛谷 P1319 / P1320 压缩技术——同一枚硬币的正反面
c++·学习·程序人生·算法
小小晓.11 小时前
C++单例模式万字详解:6种实现演进+线程安全彻底解决+CRTP终极模板
c++·单例模式
j7~13 小时前
【C++11】C++11 新特性全套详解(列表初始化、右值引用、lambda 表达式、function 与 bind 包装器等)
c++·右值引用·lambda表达式·可变参数模板·移动语义·包装器·c++11发展史