暂无链接
不回文
【问题描述】
学不会最小回文串划分的豆豆决定弃疗选择挑战非回文划分。
他想知道一个字符串 S 的最少和最多能划分成几个非回文串?
注: 如果一个字符串不是回文串,那么他是非回文串。例如()()是非回文串,而 ())(是回文串。
【输入格式】
第一行一个整数 T,表示测试数据组数。
接下来 T 行,每行一个仅由小写字母构成的字符串 S。
【输出格式】
输出 T 行,每行两个整数分别表示最小和最大划分。如果不存在非合法划分输出“-1 -1” (不含分号)。
【输入样例】
3
aaa
abba
abcb
【输出样例】
-1 -1
2 2
1 2
【数据范围】
测试点编号 数据范围 约定
1 |S |<=10 无特殊约定
2 只有 ab 两种字母
|S |<=1,000
3 无特殊约定
4
只有 ab 两种字母
5 |S |<=30,000
6 无特殊约定
7
|S |<=300,000 只有 ab 两种字母
8
9
|S |<=300,000 无特殊约定
10
对于所有数据满足,T=10。
题解
的 没写,梦想 去了,打完 走人,结果最暴力的 分还 了, !
最后的结论太玄学了,能想到算我输, 考场切题的 ,太强了 。
首先来看看最小值(貌似最小值是雅礼的签到题,但是我没去啊??? !),最小划分只有三种情况:
1.该串本身不回文,那么最小划分就是这个串,答案 ;
2.该串可以被分成 个不回文的串,此时答案 ;
3.若前面的条件都不满足,则不存在合法划分。
证明???看看题解怎么说:
再说最大值,我们可以先粗略的贪心一波:如果相邻的两个字符不相同,我们就可以把这两个字符单独划分出来(最后一个多余的字符忽略掉),这样我们求出来的答案将会是一个上限,什么时候这个答案是错的呢???,如下:
按照贪心的划分,最后会留下一个长度为 的回文串,如下:
所以只能合并一下中间的串:
这样我们的最大划分就会 。
上面的合并也有一点问题,当串本身不能被划分为两个不回文串的时候,最大划分为 ,需要特判。
代码
#include<bits/stdc++.h>
using namespace std;
const int M=3e5+5;
int T,len,base=19491001,minn,maxn,flag,cut,i;
char ch[M];
unsigned long long key[M],abc[M],cba[M];
void in(){scanf("%s",ch+1);}
bool bhw(int l,int r){return abc[r]-abc[l-1]*key[r-l+1]!=cba[l]-cba[r+1]*key[r-l+1];}
void ac()
{
len=strlen(ch+1),abc[0]=cba[len+1]=maxn=flag=cut=0,minn=-1;
for(i=1;i<=len;++i)abc[i]=abc[i-1]*base+ch[i];
for(i=len;i>=1;--i)cba[i]=cba[i+1]*base+ch[i];
for(i=1;i<len;++i)if(bhw(1,i)&&bhw(i+1,len)){minn=2;cut=1;break;}
if(bhw(1,len))minn=1;else if(cut)minn=2;else {puts("-1 -1");return;}
for(i=1;i<=len;++i)if(!flag)flag=1;else if(ch[i]!=ch[i-1])flag=0,++maxn;
if(len>=3&&len%2)
{
flag=1;
for(i=1;i<=len;i+=2)if(ch[i]!=ch[1]){flag=0;break;}
for(i=2;i<=len;i+=2)if(ch[i]==ch[1]){flag=0;break;}
if(flag)--maxn;
}
printf("%d %d\n",minn,cut?maxn:1);
}
int main()
{
scanf("%d",&T);
key[0]=1;for(i=1;i<M;++i)key[i]=key[i-1]*base;
while(T--)in(),ac();
}