HDU 6153 拓展KMP (2017CCPC)

A Secret

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 256000/256000 K (Java/Others)
Total Submission(s): 975    Accepted Submission(s): 372

Problem Description

Today is the birthday of SF,so VS gives two strings S1,S2 to SF as a present,which have a big secret.SF is interested in this secret and ask VS how to get it.There are the things that VS tell:
  Suffix(S2,i) = S2[i...len].Ni is the times that Suffix(S2,i) occurs in S1 and Li is the length of Suffix(S2,i).Then the secret is the sum of the product of Ni and Li.
  Now SF wants you to help him find the secret.The answer may be very large, so the answer should mod 1000000007.

Input

Input contains multiple cases.
  The first line contains an integer T,the number of cases.Then following T cases.
  Each test case contains two lines.The first line contains a string S1.The second line contains a string S2.
  1<=T<=10.1<=|S1|,|S2|<=1e6.S1 and S2 only consist of lowercase ,uppercase letter.

Output

For each test case,output a single line containing a integer,the answer of test case.
  The answer may be very large, so the answer should mod 1e9+7.

Sample Input

2

aaaaa

aa

abababab

aba

Sample Output

13

19

Hint

case 2:

Suffix(S2,1) = "aba",
Suffix(S2,2) = "ba",
Suffix(S2,3) = "a".

N1 = 3,
N2 = 3,
N3 = 4.
L1 = 3,
L2 = 2,
L3 = 1.

ans = (3*3+3*2+4*1)%1000000007.

题意

给你两个字符串A,B,现在要你求B串的后缀在A串中出现的次数和后缀长度的乘积和为多少。

思路

扩展KMP模板题,将s和t串都逆序以后就变成了求前缀的问题了,扩展KMP求处从i位置开始的最长公共前缀存于数组,最后通过将数组的值不为0的进行一个等差数列和的和就可以了。

代码:

 1 #include <iostream>
 2 #include <string>
 3 #include <string.h>
 4 #include <cstring>
 5 #include <algorithm>
 6 using namespace std;
 7 const int maxn = 1e6 + 10;
 8 const int mod = 1e9 + 7;
 9 typedef long long ll;
10 int cnt[maxn];
11 char A[maxn],B[maxn];
12 int Next[maxn],ex[maxn];
13 ll add(ll n)
14 {
15     ll m=((n%mod)*((n+1)%mod)/2)%mod;
16     return m;
17 }
18 void kmp(char P[])
19 {
20     int m=strlen(P);
21     Next[0]=m;
22     int j=0,k=1;
23     while(j+1<m&&P[j]==P[j+1]) j++;
24     Next[1]=j;
25     for(int i=2; i<m; i++)
26     {
27         int p=Next[k]+k-1;
28         int L=Next[i-k];
29         if(i+L<p+1) Next[i]=L;
30         else
31         {
32             j=max(0,p-i+1);
33             while(i+j<m&&P[i+j]==P[j])
34                 j++;
35             Next[i]=j;
36             k=i;
37         }
38     }
39 }
40
41 void exkmp(char P[],char T[])
42 {
43     int m=strlen(P),n=strlen(T);
44     kmp(P);
45     int j=0,k=0;
46     while(j<n&&j<m&&P[j]==T[j])
47         j++;
48     ex[0]=j;
49     for(int i=1; i<n; i++)
50     {
51         int p=ex[k]+k-1;
52         int L=Next[i-k];
53         if(i+L<p+1)
54             ex[i]=L;
55         else
56         {
57             j=max(0,p-i+1);
58             while(i+j<n&&j<m&&T[i+j]==P[j])
59                 j++;
60             ex[i]=j;
61             k=i;
62         }
63     }
64 }
65
66 int main()
67 {
68     int t;
69     scanf("%d",&t);
70     while(t--)
71     {
72         scanf("%s%s",A,B);
73         int lenA=strlen(A);
74         int lenB=strlen(B);
75         reverse(A,A+lenA);
76         reverse(B,B+lenB);
77         kmp(B);
78         memset(Next,0,sizeof(Next));
79         memset(ex,0,sizeof(ex));
80         exkmp(B,A);
81         ll ans = 0;
82         for(int i=0;i<lenA;i++)
83         {
84             if(ex[i])
85                 ans=(ans+add(ex[i])%mod)%mod;
86         }
87         printf("%lld\n",ans%mod);
88     }
89     return 0;
90 }
时间: 2024-10-04 11:53:00

HDU 6153 拓展KMP (2017CCPC)的相关文章

hdu 4300 拓展kmp

题目大意: 输入样例个数,每个样例有两行,第一行是26个字母,分别代表a~z加密后的密文:第二行代表一串密文+明文,密文一定是完整的,但明文可能不完整,让你输出最短的(密文+明文): 基本思路: 拓展kmp,因为密文是完整的,所以它的长度必然是一半以上,所以把前一半转换成明文放到另一个数组里,然后后半部分原封不动的放到该数组里,然后拓展kmp,求一下next,然后从一半以后一直往后找,找到的话,就跳出,然后基本把把问题解决了: 代码如下: #include<cstdio> #include&l

HDU 6153 A Secret(扩展KMP模板题)

A Secret Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 256000/256000 K (Java/Others) Total Submission(s): 2523    Accepted Submission(s): 934 Problem Description Today is the birthday of SF,so VS gives two strings S1,S2 to SF as a present,w

HDU 4300 Clairewd&#39;s message ( 拓展KMP )

题意 : 给你一个包含26个小写字母的明文密文转换信息字符串str,第一个表示'a'对应的密文是str[0].'b'对应str[1]--以此类推.接下来一行给你一个另一个字符串,这个字符串由密文+明文组成,但是现在后面部分的明问可能有不完整的情况(也有可能缺失只包含密文),问你现在最少需要补充多多少个字符串才能使得字符串变成完整的满足==>密文+密文对应的明文 组成的字符串,将这个完整的字符串输出出来. 分析 : 冷静分析一下可以发现,在给出的残缺字符串中,前面的一半肯定是属于密文的!如果不是这

HDU 4300 Clairewd‘s message 拓展KMP入门

HDU 4300 Clairewd's message 拓展KMP入门 题意 原题链接 这个题关键是要读懂题意,我做的时候就没有读懂,泪.题意是说给你的一个两个字符串,一个是26个字母密码表,依次对应替换的字母.然后给你一个字符串,这个字符串是不完整的(完整的应该是前半部分是加密的,后半部分是解密了的),然而,给你的字符串一定是加密的部分+一部分解密的部分(可以是全部,也可以是没有),让你求出最短的完整字符串,包括密文和明文: 解题思路 考虑给出的字符串S加密部分一定全部给出,所以给出的字符串的

HDU - 3613 Best Reward(manacher或拓展kmp)

传送门:HDU - 3613 题意:给出26个字母的价值,然后给你一个字符串,把它分成两个字符串,字符串是回文串才算价值,求价值最大是多少. 题解:这个题可以用马拉车,也可以用拓展kmp. ①Manacher:先记录下第i个字符的价值,然后求前缀和.然后遍历分的位置,分别判断前半段和后半段是否为回文串,是回文串的加上这段的价值(前缀和相减),更新最大价值. 1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int p[1000100],v

HDU 4300 Clairewd’s message(初遇拓展KMP)

昨晚一不小心学了拓展KMP,被虐了一晚,最终是这份资料救了我...http://wenku.baidu.com/view/8e9ebefb0242a8956bece4b3.html 说得简单易懂. 然后学了kuangbin的模版: /* * 扩展KMP算法 */ //next[i]:x[i...m-1]与x[0...m-1]的最长公共前缀 //extend[i]:y[i...n-1]与x[0...m-1]的最长公共前缀 void pre_EKMP(char x[],int m,int next[

HDU 3613 Best Reward(求前后缀回文 拓展KMP or Manacher)

题目大意: 给个字符串X,要把X分成两段T1,T2,每个字母都有一个对应的价值,如果T1,T2是回文串(从左往右或者从右往左读,都一样),那么他们就会有一个价值,这个价值是这个串的所有字母价值之和,如果不是回文串,那么这串价值就为0.问最多能获得多少价值? 思路: 把字符串X逆序后得到字符串Y 让X去匹配Y ,匹配的长度满足extend[i] + i == len,  len=|X|.    的那么X与y的匹配部分是回文串,这不难理解,画图即可 总复杂度是O(n),由于这是求前缀和后缀的回文,用

HDU 3613 Best Reward(拓展KMP算法求解)

题目链接: https://cn.vjudge.net/problem/HDU-3613 After an uphill battle, General Li won a great victory. Now the head of state decide to reward him with honor and treasures for his great exploit. One of these treasures is a necklace made up of 26 differe

Simpsons’ Hidden Talents HDU - 2594(拓展kmp)

Sample Input clinton homer riemann marjorie Sample Output 0 rie 3 看输出才题意...拓展kmp特征很明显嘛....注意开始就匹配到尾的情况 #include <iostream> #include <cstdio> #include <sstream> #include <cstring> #include <map> #include <set> #include &