【扩展kmp】HDU 6153 A Secret

acm.hdu.edu.cn/showproblem.php?pid=6153

【题意】

  • 给定字符串A和B,求B的所有后缀在A中出现次数与其长度的乘积之和
  • A和B的长度最大为1e6

【思路】

  • 把A和B同时反转,相当于求B的所有前缀在A中出现次数与其长度的乘积之和
  • 换个角度,相当于A中每出现一个B的前缀,答案中就要加上该前缀的长度
  • 考虑A中每个位置对答案的贡献,A[i...lenA-1]与B的最长公共前缀是x,则B中的前缀B[0...1],B[0....2]...B[0....x]都在A中出现,那么答案就要加上x*(x+1)/2
  • 求S中的每个后缀与T的最长公共前缀用扩展KMP,时间复杂度是线性的

【AC】

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const ll mod=1e9+7;
 5 const int maxn=1e6+2;
 6 char s[maxn];
 7 char t[maxn];
 8 int nxt[maxn];
 9 int extend[maxn];
10 ll ans;
11
12 void add(ll n)
13 {
14     ll tmp=((n%mod)*((n+1)%mod)/2)%mod;
15     ans=(ans+tmp)%mod;
16 }
17 void pre_EKMP(char x[],int m,int nxt[])
18 {
19     nxt[0]=m;
20     int j=0;
21     while(j+1<m && x[j]==x[j+1]) j++;
22     nxt[1]=j;
23     int k=1;
24     for(int i=2;i<m;i++)
25     {
26         int p=nxt[k]+k-1;
27         int L=nxt[i-k];
28         if(i+L<p+1) nxt[i]=L;
29         else
30         {
31             j=max(0,p-i+1);
32             while(i+j<m && x[i+j]==x[j]) j++;
33             nxt[i]=j;
34             k=i;
35         }
36     }
37 }
38
39 void EKMP(char x[],int m,char y[],int n,int nxt[],int extend[])
40 {
41     pre_EKMP(x,m,nxt);//子串
42     int j=0;
43     while(j<n && j<m &&x[j]==y[j]) j++;
44     extend[0]=j;
45     int k=0;
46     for(int i=1;i<n;i++)
47     {
48         int p=extend[k]+k-1;
49         int L=nxt[i-k];
50         if(i+L<p+1) extend[i]=L;
51         else
52         {
53             j=max(0,p-i+1);
54             while(i+j<n && j<m && y[i+j]==x[j]) j++;
55             extend[i]=j;
56             k=i;
57         }
58     }
59 }
60
61 int main()
62 {
63     int T;
64     scanf("%d",&T);
65     while(T--)
66     {
67         scanf("%s",s);
68         scanf("%s",t);
69         int ls=strlen(s);
70         int lt=strlen(t);
71         for(int i=0;i<ls/2;i++)
72         {
73             swap(s[i],s[ls-1-i]);
74         }
75         for(int i=0;i<lt/2;i++)
76         {
77             swap(t[i],t[lt-1-i]);
78         }
79         EKMP(t,lt,s,ls,nxt,extend);
80         ans=0;
81         for(int i=0;i<ls;i++)
82         {
83             add(extend[i]);
84         }
85         printf("%I64d\n",ans);
86     }
87     return 0;
88 } 

扩展kmp

时间: 2024-08-04 10:18:21

【扩展kmp】HDU 6153 A Secret的相关文章

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 6153 A Secret(扩展kmp)

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

扩展KMP - HDU 4333 Revolving Digits

Revolving Digits Problem's Link: http://acm.hdu.edu.cn/showproblem.php?pid=4333 Mean: 给你一个字符串,你可以将该字符串的任意长度后缀截取下来然后接到最前面,让你统计所有新串中有多少种字典序小于.等于.大于原串. analyse: KMP的经典题. 首先我们将原串扩展成两倍,算一遍扩展KMP(自匹配),时间复杂度O(n). 这样一来,我们就得到了eKMP[i],eKMP[i]代表s[i...len-1]与s的最长

扩展KMP --- HDU 3613 Best Reward

Best Reward Problem's Link:   http://acm.hdu.edu.cn/showproblem.php?pid=3613 Mean: 给你一个字符串,每个字符都有一个权值(可能为负),让你将这个字符串分成两个字串,使得这两个子串的价值之和最大.一个子串价值的计算方法:如果这个子串是回文串,那么价值就是这个子串所有字符权值之和:否则价值为0. analyse: 经典的扩展KMP算法运用. 假设输入串为s,那么我们首先:strcpy(s1,s)     ;      

2017中国大学生程序设计竞赛 - 网络选拔赛 HDU 6153 A Secret KMP,思维

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6153 题意:给了串s和t,要求每个t的后缀在在s中的出现次数,然后每个次数乘上对应长度求和. 解法:关键在于想到把s和t都翻转之后,把t求next,然后用t去匹配s,在匹配过程中把fail指针跳到的地方加1,但是还没完,最后需要反向遍历第二个串将大串对小串的贡献加上去就可以了. 这道题是很多现场AC的代码是有漏洞的,比如bazbaba,bazbaba这个答案是34,但是很多现场AC的代码会输出31.

HDU 6153 A Secret (KMP)

题意:给定两个串,求其中一个串 s 的每个后缀在另一个串 t 中出现的次数. 析:首先先把两个串进行反转,这样后缀就成了前缀.然后求出 s 的失配函数,然后在 t 上跑一遍,如果发现不匹配了或者是已经完全匹配了,要计算,前面出现了多少个串的长度匹配也就是 1 + 2 + 3 + .... + j 在 j 处失配,然后再进行失配处理.注意别忘了,匹配完还要再加上最后的. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000"

HDU 6153 A Secret 套路,求解前缀在本串中出现的次数

http://acm.hdu.edu.cn/showproblem.php?pid=6153 首先相当于翻转两个串,然后求s2前缀在s1中出现的次数. 这是一个套路啦 首先把两个串结合起来,中间加一个'%'之类的分割 设dp[i]表示前缀1---i在本串中的出现次数和 那么从后开始dp,所有dp值一开始都是1,表示前缀出现了一次,就是自己本身. 转移,设当前去到第i位,则dp[next[i + 1] - 1] += dp[i] 就是ABACABA这样,已经知道了ABACABA出现了一次,然后前后

HDU 6153 A Secret

题意:给定两个串,求其中一个串 s 的每个后缀在另一个串 t 中出现的次数. 题解:把两个串都 reverse 一下,给 t 做个 KMP 之后让 s 在 KMP 出来的结果上跑一遍就好了. kmp模板题. #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<algorithm> #include

HDU 4300 (扩展KMP或KMP)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4300 题意:说实话,看半天题目,愣是没看懂,百度题意才看懂,大概意思就是:第一个串串为匹配串,第i个代表字母顺序中的第i个,比如第一个是q,那么,q就代表a. 第二个串是密文+明文,密文全部都有,但明文可能不全,输出完整的密文+明文. 题解:有两种做法,第一种,用扩展KMP: 1.先把s2砍半,前面一半必定为密文,后面一半可能是密文+明文. 2.把前面的一半转化成明文. 3.用后面的和前面的找最长公