题目链接:点击查看

题目大意:给出两个字符串a和b,我们首先定义L:字符串b当前的后缀子字符串长度,N:字符串b当前的后缀在字符串a中出现的次数,现在询问,对于字符串b的每一个后缀,求出L*N之和,答案对于1e9+7取模

题目分析:首先我们需要知道一个next数组的性质,也可以说是利用动态规划延伸出来的一个公式吧:

for(int i=1;i<=n;i++)dp[i]=1;
for(int i=n;i>=1;i--)dp[next[i]]+=dp[i];

用上面公式递推出来的dp数组,dp[i]就代表截止到i的前缀在主串中出现的次数

对于这个题目,我们可以再做一次扩展,对于一个字符串a和字符串b,我们将其合成为字符串c=b+'#'+a(加上井号是为了防止中间重叠部分的影响,井号可以替换为其他任意不在字符串中出现的字符)

那么我们对于字符串c求一次dp_c,在对字符串b求一次dp_b,根据容斥原理我们可以知道dp_c[i]-dp_b[i]就是当前b中截止到i的前缀在字符串a中出现的次数

有了上面的扩展,我们一开始就可以将字符串a和字符串b翻转,将对后缀的操作全部转换成对前缀的操作,然后就能很轻松的解决这个问题了


2020.1.31更新:

练习扩展KMP时又碰到这个题了,前来更新一下,相对于KMP的解法来说,扩展KMP的解法更容易想到且更容易实现,因为一般的扩展KMP求出的extend[ i ]数组表示的是s[ i ]的后缀与 t 的最长公共前缀,而这个题目要求的是关于后缀的信息,我们不妨将两个串都反转一下,这样extend[ i ]数组表示的就是s[ 0 ~ stelen(s) - i ]这个前缀与 t 的最长公共后缀了,这样我们利用等差数列求和公式就可以直接计算贡献了,因为假如extend[ i ] = 2 ,那么代表着在字符串 t 中,长度为 1 和长度为 2 的后缀,在字符串 s 当前的前缀 s[ 0 ~ stelen(s) - i ]中出现了一次,那么累计贡献就是 1 + 2 = 3次

代码:

KMP+DP:

#include<iostream>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#include<cmath>
#include<cctype>
#include<stack>
#include<queue>
#include<list>
#include<vector>
#include<set>
#include<map>
#include<sstream>
#include<unordered_map>
using namespace std;typedef unsigned long long ull;typedef long long LL;const int inf=0x3f3f3f3f;const int N=2e6+100;const int mod=1e9+7;int nx[N];int dp_c[N],dp_b[N];void getnext(string& s)
{nx[0]=-1;int i=0,j=-1;while(i<s.size()){if(j==-1||s[i]==s[j])nx[++i]=++j;elsej=nx[j];}
}int main()
{
//  freopen("input.txt","r",stdin);ios::sync_with_stdio(false);int n;cin>>n;while(n--){string a,b;cin>>a>>b;reverse(a.begin(),a.end());reverse(b.begin(),b.end());    string c=b+'#'+a;getnext(c);for(int i=1;i<=c.size();i++)dp_c[i]=1;for(int i=c.size();i>=1;i--)dp_c[nx[i]]+=dp_c[i];getnext(b);for(int i=1;i<=b.size();i++)dp_b[i]=1;for(int i=b.size();i>=1;i--)dp_b[nx[i]]+=dp_b[i];LL ans=0;for(LL i=1;i<=b.size();i++)ans=(ans+i*(dp_c[i]-dp_b[i]))%mod;cout<<ans<<endl;}return 0;
}

扩展KMP:

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<sstream>
using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=1e6+100; //字符串长度最大值const int mod=1e9+7;int Next[N],extend[N];char s[N],t[N];//预处理计算Next数组
void getNext(char str[])
{int i=0,j,po,len=strlen(str);Next[0]=len; //初始化Next[0]while(str[i]==str[i+1] && i+1<len) i++; Next[1]=i; //计算Next[1]po=1; //初始化po的位置for(i=2;i<len;i++){if(Next[i-po]+i < Next[po]+po) //第一种情况,可以直接得到Next[i]的值Next[i]=Next[i-po];else //第二种情况,要继续匹配才能得到Next[i]的值{j = Next[po]+po-i;if(j<0) j=0; //如果i>po+Next[po],则要从头开始匹配while(i+j<len && str[j]==str[j+i]) j++; Next[i]=j;po=i; //更新po的位置}}
}//计算extend数组
void EXKMP(char s1[],char s2[])
{int i=0,j,po,len=strlen(s1),l2=strlen(s2);getNext(s2); //计算子串的Next数组while(s1[i]==s2[i] && i<l2 && i<len) i++; extend[0]=i;po=0; //初始化po的位置for(i=1;i<len;i++){if(Next[i-po]+i < extend[po]+po) //第一种情况,直接可以得到extend[i]的值extend[i]=Next[i-po];else //第二种情况,要继续匹配才能得到extend[i]的值{j = extend[po]+po-i;if(j<0) j=0; //如果i>extend[po]+po则要从头开始匹配while(i+j<len && j<l2 && s1[j+i]==s2[j]) j++; extend[i]=j;po=i; //更新po的位置}}
}int main()
{
//  freopen("input.txt","r",stdin);
//  ios::sync_with_stdio(false);int w;cin>>w;while(w--){scanf("%s%s",s,t);reverse(s,s+strlen(s));reverse(t,t+strlen(t));getNext(s);EXKMP(s,t);int len=strlen(s);LL ans=0;for(int i=0;i<len;i++)ans=(ans+1LL*extend[i]*(extend[i]+1)/2)%mod;printf("%lld\n",ans);}return 0;
}

HDU - 6153 A Secret(KMP的next数组性质/扩展KMP)相关推荐

  1. hdu 6153 A Secret kmp + dp

    传送门 文章目录 题意: 思路: 题意: 给你两个串a,ba,ba,b,让你求对于bbb的每个后缀,设其长度为lenlenlen,其在aaa中出现的次数为cntcntcnt,那么他的贡献为len∗cn ...

  2. CodeForces - 432D Prefixes and Suffixes(KMP的next数组性质)

    题目链接:点击查看 题目大意:给出一个字符串,求满足条件的所有子字符串在主串中出现的次数,条件就是当前子字符串在主串中既是前缀也是后缀 题目分析:因为今天小冰给我讲了一个与next数组配合的dp,也就 ...

  3. HDU - 6629 string matching(扩展KMP)

    题目链接:点击查看 题目大意:给出一个字符串 s 和一个暴力程序,用于求解 s 的每个后缀和原字符串的最长公共前缀,现在问一共需要执行多少次比较操作 题目分析:首先肯定不能暴力去模拟,时间复杂度n*n ...

  4. Oulipo HDU - 1686 (使用扩展kmp进行讨伐!)

    题目链接 题意:给你两个字符串s,t.让你求在s中t出现了多少次. 解题思路: kmp做法点这里 使用扩展kmp.构建一个新字符串k=t+▲+s ▲为分隔符,保证不会影响s求z函数. 对k使用扩展km ...

  5. 【算法小结】KMP及扩展KMP

    " Ctrl AC!一起 AC!" 目录 next数组: KMP算法 1.判断模式串是否为文本串的子串 2.判断模式串在文本串中出现次数 nextval数组: 扩展KMP算法: n ...

  6. hdu 4125 Moles(kmp+树状数组)

    题目链接:hdu 4125 Moles 题意: 给你n个数,让你按键值建一个平衡二叉树,然后奇数为0,偶数为1,然后可以遍历这颗树得到一个欧拉序列,现在给你一个串,问你出现了几次. 题解: 建树的时候 ...

  7. HDU - 1358 Period(KMP的next数组求最小循环节)

    题目链接:点击查看 题目大意:给出一个长度为n的字符串,问有哪些前缀是周期性字符串 题目分析:因为n给的很大,所以肯定不能暴力判断了,我们可以巧妙的利用kmp的next数组进行判断,next数组有一个 ...

  8. HDU - 3746 Cyclic Nacklace(KMP的next数组判循环节)

    题目链接:点击查看 题目大意:现在规定想要制作一串珍珠手链,需要用到两段一模一样的字符串首位相接而成,现在给定一个字符串,问最少需要添加几个珍珠才能满足条件 题目分析:一开始以为是个简单的模拟题,但后 ...

  9. 扩展KMP --- HDU 3613 Best Reward

    Best Reward Problem's Link:   http://acm.hdu.edu.cn/showproblem.php?pid=3613 Mean: 给你一个字符串,每个字符都有一个权 ...

最新文章

  1. openGL 入门 2--顶点数组对象 VAO 和 缓存对象 VBO
  2. Codeforces round 1083
  3. PHP:验证邮箱合法性
  4. tqdm: ‘module‘ object is not callable
  5. java 最新sql注入原因以及预防方案(易理解)
  6. 解决Bazel:Error: LinkageError occurred while loading main class com.google.devtools.build.lib.bazel.
  7. 04.内置analyzer和analyze-API使用
  8. C语言 指针数组 - C语言零基础入门教程
  9. 信息学奥赛一本通(1315:【例4.5】集合的划分)
  10. 线性代数 —— 线性基与前缀线性基
  11. Cmake构建_设置debug与release输出路径
  12. 《管理3.0》读书笔记
  13. java如何避免死锁_java并发编程如何预防死锁
  14. html5空白站位符号,空格代码(隐形空白符号)
  15. 这一篇彻底说清楚了!乐高,编程,机器人到底要不要学?
  16. 阿里腾讯裁员30%,互联网大厂此举预示着什么?
  17. 转载多线程下载(HTTPWebRequest)
  18. 如何获取计算机网络地址,如何查看电脑获取到的IP地址?
  19. React Native与原生的图片交互问题
  20. Android ListView 异步加载图片

热门文章

  1. 创建spring配置
  2. MySQL高级 - 复制 - 集群搭建
  3. SpringSecurity案例之认证服务security配置
  4. 对文本的内容进行排序
  5. Lambda表达式的无参数无返回值的练习
  6. spring配置详解-三种对象创建方式_
  7. Rocketmq原理最佳实践
  8. android flux 与mvp,使用 MVP 时在设计上的考量
  9. linux 内核dmesg,linux內核調試kmsg,dmesg
  10. 学习ASP.NET Core Razor 编程系列十八——并发解决方案