BZOJ 2160 拉拉队排练 详解

博客介绍了如何解决一个关于寻找字符串中和谐小群体(回文串)的问题。通过马拉车算法找出所有回文串,然后计算前K个回文串长度的乘积对19930726取余的结果。博客详细阐述了问题描述、输入输出、样例解释、解题思路和关键步骤,包括如何利用马拉车算法、快速幂计算乘积。
摘要由CSDN通过智能技术生成

Description

艾利斯顿商学院篮球队要参加一年一度的市篮球比赛了。拉拉队是篮球比赛的一个看点,好的拉拉队往往能帮助球队增加士气,赢得最终的比赛。所以作为拉拉队队长的楚雨荨同学知道,帮助篮球队训练好拉拉队有多么的重要。拉拉队的选拔工作已经结束,在雨荨和校长的挑选下,n位集优秀的身材、舞技于一体的美女从众多报名的女生中脱颖而出。这些女生将随着篮球队的小伙子们一起,和对手抗衡,为艾利斯顿篮球队加油助威。一个阳光明媚的早晨,雨荨带领拉拉队的队员们开始了排练。n个女生从左到右排成一行,每个人手中都举了一个写有26个小写字母中的某一个的牌子,在比赛的时候挥舞,为小伙子们呐喊、加油。雨荨发现,如果连续的一段女生,有奇数个,并且他们手中的牌子所写的字母,从左到右和从右到左读起来一样,那么这一段女生就被称作和谐小群体。现在雨荨想找出所有和谐小群体,并且按照女生的个数降序排序之后,前K个和谐小群体的女生个数的乘积是多少。由于答案可能很大,雨荨只要你告诉她,答案除以19930726的余数是多少就行了。

Input

输入为标准输入。第一行为两个正整数n和K,代表的东西在题目描述中已经叙述。接下来一行为n个字符,代表从左到右女生拿的牌子上写的字母。

Output

输出为标准输出。输出一个整数,代表题目描述中所写的乘积除以19930726的余数,如果总的和谐小群体个数小于K,输出一个整数-1。

Sample Input

5 3
ababa

Sample Output

45

样例说明

和谐小群体女生所拿牌子上写的字母从左到右按照女生个数降序排序后为ababa, aba, aba, bab, a, a, a, b, b,前三个长度的乘积为。

HINT

总共20个测试点,数据范围满足:

在这里插入图片描述

题意分析

对于一个长度为n的给定字符串,找出其中所有的回文字符串,按照回文串的长度降序排列,计算出前K个长度值的乘积(对19930726的余数),如果回文串的个数小于K个,则输出-1.
题中给的例子:对于一个长度为n=5的字符串“ababa”,计算出前k=3个回文串长度的乘积。
“ababa”的回文串从左到右共有9个(单独一个字符也算回文):“a”、“b”、“a”、“aba”、“b”、“bab”、“a”、“ababa”、“aba”,如果按降序排列的话是:“ababa”、“aba”、“bab”、“aba”、“a”、“b”、“a”、“b”、“a”,其长度分别是5、3、3、3、1、1、1、1、1,前三个的长度是5、3、3,所以乘积是5×3×3=45

解题思路

首先,这个题需要找出给定字符串的所有回文子串的长度,这个显然可以用马拉车算法,马拉车算法计算的数组(在本文中成为数组f[],在讲解manachar算法的那个帖子中称为数组p[])f[]的值就是每个字符为中心的回文串的半径长度,所以根据数组f[]计算出每种回文串的长度及其回文串的个数,最后按降序把长度最大的K个回文串长度值连乘得到结果即可,连乘可以使用快速幂的方法。

这个过程大体可以分为四步:
第一步:对原串使用manachar算法,计算出数组f[],记录下以每一个字符为中心的回文串半径长度,如“ababa”的f[]={0,1,2,1,0}。

第二步:通过对数组f[]的处理,得出每种回文串的长度 以及该种回文串的个数,比如“ababa”中,长度为5的回文串有1个(“ababa”),长度为3的回文串有3个(“aba”、“bab”、“aba”),长度为1的回文串有5个(“a”、“b”、“a”、“b”、“a”),总共有9个回文串。

第三步:看看回文串总数是不是大于K,如果小于,则输出“-1”,否则,从大到小连乘前k个回文串的长度,按照快速幂的方法连乘,例如“ababa”共有9个回文串,长度为5的有1个,长度为3的有3个,长度为1的有5个,则 ans=5×3×3 ,即 51×32=45

在这个过程中,还有一些细节问题需要注意,下面就分别详细介绍三个步骤

第一步

第一步是对原串用manachar算法求出它的f[]数组。manachar算法详细的介绍写过专门的帖子介绍,这里不赘述。但在这里有一些与标准manachar算法不一样的地方需要注意:manachar算法一般要在原串中插入“#”使得原串的长度都变成奇数再进行处理,插入“#”后的串也叫“双倍串”,长度是原来的2倍+1。而这个题中明确说要统计的和谐小群体的人数是奇数个。所以在这个题中,就不用往原串中插入“#”了,原来的串也可以叫做“单倍串”。
为什么呢,比如“ababa”,他的f[]={0、1、2、1、0},每一个f[i]的值是以第i个字符为中心的回文串的半径,如f[3]=2就是第3个字符“a”为中心的回文“ababa”的半径是2,因为是以某一个字符为中心,所以回文串的长度肯定是奇数的。
再比如“babbab”,左边的“bab”和右边的“bab”是对称相等的,所以“babbab”是一个长度为6的回文串,但由于数组f[]是以某一个字符为中心的回文串半径,所以他的f[]={0、1、0、0、1、0},因为是偶数长度的回文串,所以无论是以第3个字符“b”还是第4个字符“b”为中心,都没有回文串(回文串半径为0),因此偶数长度的回文串就不会统计在内了。
这一段的代码如下:

    for (i=1;i<=n;i++)		//n为字符串长度
    {
   
        if (i<=mx) f[i]=min(mx-i,f[2*id-i]);
        else f[i]=0;
        while (s[i+f[i]+1]==s[
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值