[2018.07.10 T2]不回文

暂无链接

不回文

【问题描述】

学不会最小回文串划分的豆豆决定弃疗选择挑战非回文划分。

他想知道一个字符串 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。

题解

O(n2) O ( n 2 ) dp d p 没写,梦想 T3 T 3 去了,打完 10 10 走人,结果最暴力的 10 10 分还 T T 了, sht s h ∗ t

最后的结论太玄学了,能想到算我输, orz o r z 考场切题的 Rockdu R o c k d u ,太强了 %%% % % %

首先来看看最小值(貌似最小值是雅礼的签到题,但是我没去啊??? sht s h ∗ t !),最小划分只有三种情况:

1.该串本身不回文,那么最小划分就是这个串,答案 =1 = 1

2.该串可以被分成 2 2 个不回文的串,此时答案=2

3.若前面的条件都不满足,则不存在合法划分。

证明???看看题解怎么说:

图片2.png

再说最大值,我们可以先粗略的贪心一波:如果相邻的两个字符不相同,我们就可以把这两个字符单独划分出来(最后一个多余的字符忽略掉),这样我们求出来的答案将会是一个上限,什么时候这个答案是错的呢???,如下:

jajbjcjdjejfjpjojkj j a j b j c j d j e j f j p j o j k j

按照贪心的划分,最后会留下一个长度为 3 3 的回文串,如下:

ja | jb | jc | jd | je | jf | jp | jo | jkj

所以只能合并一下中间的串:

ja | jb | jc | jdjej | fj | pj | oj | kj j a   |   j b   |   j c   |   j d j e j   |   f j   |   p j   |   o j   |   k j

这样我们的最大划分就会 1 − 1

上面的合并也有一点问题,当串本身不能被划分为两个不回文串的时候,最大划分为 1 1 <script type="math/tex" id="MathJax-Element-3801">1</script>,需要特判。

代码
#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();
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ShadyPi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值