hdu 3336 Count the string 用心写的题解

hdu 3336 Count the string 用心写的题解ProblemDescriptionItiswellknownthatAekdyCoinisgoodatstringproblemsaswellasnumbertheoryproblems.Whengivenastrings,wecanwritedownallthenon-emptyprefixesofthisstring.Fo

大家好,又见面了,我是你们的朋友全栈君。

Problem Description
It is well known that AekdyCoin is good at string problems as well as number theory problems. When given a string s, we can write down all the non-empty prefixes of this string. For example:
s: “abab”
The prefixes are: “a”, “ab”, “aba”, “abab”
For each prefix, we can count the times it matches in s. So we can see that prefix “a” matches twice, “ab” matches twice too, “aba” matches once, and “abab” matches once. Now you are asked to calculate the sum of the match times for all the prefixes. For “abab”, it is 2 + 2 + 1 + 1 = 6.
The answer may be very large, so output the answer mod 10007.

Input
The first line is a single integer T, indicating the number of test cases.
For each case, the first line is an integer n (1 <= n <= 200000), which is the length of string s. A line follows giving the string s. The characters in the strings are all lower-case letters.

Output
For each case, output only one number: the sum of the match times for all the prefixes of s mod 10007.

Sample Input
1
4
abab

Sample Output
6

Author
foreverlin@HNU

Source
HDOJ Monthly Contest – 2010.03.06

Recommend
lcy

首先题目大意很好搞懂,就是给一个字符串s,求它的所有前缀的匹配次数。这道题做了两个星期,特此来写个题解。
首先最智障的方法,对每一个前缀都kmp一次求匹配次数。这么做当然会超时,但能给我们一些思考。
然后我们试着优化算法。第一个比较容易想到的优化是剪枝:当s[I]的前缀在s中的匹配次数为1时,则对于任何j>I,s【j】的前缀在s中的匹配次数都是1.但是这个剪枝遇到形如’aaaaa’字符串就失效了。

知识补充:自匹配:对一个字符串,前k个字符和后k个字符一样,就称其构成了一个长度为k的自匹配。
真前缀:前缀不算自己。

接着继续优化。这里贴一篇我觉得很好的博文的内容:(以下内容为转载)(斜体加粗内容为补充)
要理解next数组的含义:next【i】表示s【i】的真前缀中,最长自匹配的长度,具体见下面例子。
根据next数组,找到一个匹配的后缀ans+1,接着对next回溯一直到为0,相当于把子串里蕴含的前缀子串也找出来,举个例子:
s a b a b a
i 0 1 2 3 4 5
next[i] -1 0 0 1 2 3
cnt[0]=0;(无真前缀)
cnt[1]=1;(自身)
cnt[2]=1;(自身)
cnt[3]=2;(“aba”中“a”构成了自匹配)
cnt[4]=2;(“abab”中“ab”构成了自匹配)
cnt[5]=3;(“ababa”中“a”“aba”构成了自匹配)
ans=9;

具体的,拿next【5】这个字符举个例子。首先,next【5】==3,说明了s【5】的一个真前缀:s【0】到s【4】中,有一个长度为3的最长自匹配。也就是s【0】==s【2】,s【1】==s【3】,s【2】==s【4】。那么很显然,s【0】到s【2】这个长度为3的子串,也就是‘aba’,在s【2】到s【4】出现了一次。

那么,接下来,也是这道题最关键的部分,我们如何算出答案呢?我们考虑对于每一个字符,都对它的真前缀做一个扫描,计算所有以这个字符前一个字符(因为是真前缀)结尾的匹配个数,记作cnt【i】。或者简单的说,cnt【i】就是它的真前缀中自匹配的个数。注意,这里的匹配指的是所有的可行的匹配。比如,对于字符串“ababa”,在考虑cnt【4】时,就要计算”a” “ab” “aba” “abab”分别的,以s【3】也就是b结尾的匹配个数。最后,我们把这些匹配个数一加,就是所求的匹配个数了。具体的,就是cnt【4】=0+1+0+1=2
那么这个和next表又有什么关系呢?还是拿上面的例子。对于next【5】==3,我们知道了在s【5】真前缀中有一个长度为3的最长自匹配。那么,我们通过next【3】==1知道,在s【3】真前缀中有一个长度为1的最长自匹配。那么想象一下,这个长度为1的自匹配是否也出现在了s【5】的真前缀中并且以s【4】结尾?

答案是肯定的。具体的,“aba”是“ababa”的一个最长自匹配,“a”是“aba”的一个最长自匹配。那么,“a”是“ababa”的一个自匹配。

或者说,“a”是cnt【5】(虚构的哨兵)中的一项。
这时候我们再翻回去看一下cnt【】,是不是懂了呢?
我们就可以得到如下代码:

for(int i = 1; i <= len; i++)  
        {  
            int tmp = next[i];  
            while(tmp)  
            {  
                ans = (ans + 1) % MOD;  
                tmp = next[tmp];  
            }  
        }  

但是,聪明的同学会发现,这段代码其实仍有可能超时。它的复杂度就是答案。
我们可以将其改进成为dp

dp[0]=0;
        for(int i=1;i<=n;i++)
        { dp[i]=(dp[N[i]]+1)%10007; sum=(sum+dp[i])%10007; }

这就是这个程序的主体框架了。
最后,感谢卿爷,感谢TCgogogo的博客,他的博客让我彻底搞懂这道题:

http://blog.csdn.net/tc_to_top/article/details/43730479

,感谢邓俊辉老师的数据结构公开课和数据结构教材。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/163378.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 嵌入式和pc的区别_嵌入式系统基础教程第2版

    嵌入式和pc的区别_嵌入式系统基础教程第2版Atitit嵌入式系统与pc系统的对比目录1.哈佛结构和冯诺依曼结构普林斯顿结构区12.中断程序类库调用13.指令集三大流程语句与运算语句赋值语句14.异常处理25.存储管理(内存26.安卓嵌入式26.1.Python嵌入式26.2.Java嵌入式开发27.常见软件功能区别27.1.Dbn…

    2022年10月4日
    4
  • beta分布介绍

    beta分布介绍相信大家学过统计学的都对正态分布二项分布均匀分布等等很熟悉了 但是却鲜少有人去介绍 beta 分布的 用一句话来说 beta 分布可以看作一个概率的概率分布 当你不知道一个东西的具体概率是多少时 它可以给出了所有概率出现的可能性大小 举一个简单的例子 熟悉棒球运动的都知道有一个指标就是棒球击球率 battingavera 就是用一个运动员击中的球数除以击球的总数 我们一般认为 0 26

    2025年12月9日
    4
  • pycharm2018激活码 pycharm激活码_软件一键无痕看怎么使用的

    pycharm2018激活码 pycharm激活码_软件一键无痕看怎么使用的PyCharm激活码最新破解教程,Mac版激活至2299年,PyCharm激活码2021.3.3

    2022年4月20日
    159
  • Oracle ORA-01017: invalid username/password;logon denied问题解决「建议收藏」

    Oracle ORA-01017: invalid username/password;logon denied问题解决「建议收藏」问题描述:ORA-01017:invalidusername/password;logondenied问题分析:1、该登录用户没有权限。解决办法:第一步,打开SQLPlus第二步,输入用户名和密码。第三步,输入alterusersystemaccountlock;给用户解锁。第四步,输入connectsystem/123456assysdba给用户授权。注:system是用户名,123456是用户的密码。…

    2022年5月20日
    118
  • 多重共线性检验-方差膨胀系数(VIF)

    多重共线性检验-方差膨胀系数(VIF)  方差膨胀系数(varianceinflationfactor,VIF)是衡量多元线性回归模型中复(多重)共线性严重程度的一种度量。它表示回归系数估计量的方差与假设自变量间不线性相关时方差相比的比值。  多重共线性是指自变量之间存在线性相关关系,即一个自变量可以是其他一个或几个自变量的线性组合。若存在多重共线性,计算自变量的偏回归系数时矩阵不可逆。其表现主要有:整个模型的方差分析…

    2022年6月11日
    148
  • format(format c)

    a-antemeridiemandpostmeridiemd-dayofmonth(noleadingzero)dd-dayofmonth(twodigit)o-dayofyear(noleadingzeros)oo-dayofyear(threedigit)D-daynameshortDD-…

    2022年4月10日
    51

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号