• 题解 CH1809 【匹配统计】


    题目链接:Link

    Problem

    Solution

    首先不难想到字符串Hash的做法,枚举A中的每个位置,二分匹配长度即可,时间复杂度(O(n))
    很明显正解应该要用KMP,但对于匹配出的一个f[i]我们只能知道“有一次长度至少为f[i]的匹配”,同时还可能会漏掉一些匹配位,怎么办?
    基于值域的前缀和
    即令cnt[x]=长度至少为x的匹配位的个数,易得答案等于cnt[x]-cnt[x+1]。
    因此,我们可以先把由f数组可直接得出的匹配位统计进cnt数组。
    对于哪些被遗忘的匹配位,由KMP的基本引理2可得分别是f[i]=nxt[i],nxt[nxt[i]],...。倒序循环累加一下即可。

    Code

    字符串Hash:

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef unsigned long long ULL;
    const int maxn=200005;
    const ULL P=13141;
    char A[maxn],B[maxn];
    ULL pm[maxn],ha[maxn],hb[maxn];
    int N,M,Q,cnt[maxn];
    inline int match(int p)
    {
    	int L=0,R=min(N-p+1,M),M,res=0;
    	while(L<=R)
    	{
    		M=(L+R)>>1;
    		if(ha[p+M-1]-ha[p-1]*pm[M]==hb[M]) L=M+1,res=M;
    		else R=M-1;
    	}
    	return res;
    }
    int main()
    {
    #ifdef local
    	freopen("pro.in","r",stdin);
    #endif
    	scanf("%d%d%d",&N,&M,&Q);
    	scanf("%s%s",A+1,B+1);
    //	printf("A=%s B=%s
    ",A+1,B+1);
    	pm[0]=1;
    	for(int i=1;i<maxn;i++) pm[i]=pm[i-1]*P;
    	for(int i=1;i<=N;i++) ha[i]=ha[i-1]*P+(A[i]-'a'+1);
    	for(int i=1;i<=M;i++) hb[i]=hb[i-1]*P+(B[i]-'a'+1);
    	for(int i=1;i<=N;i++)
    	{
    		cnt[match(i)]++;
    //		printf("match(%d)=%d
    ",i,match(i));
    	}
    	while(Q-->0)
    	{
    		int x; scanf("%d",&x);
    		printf("%d
    ",cnt[x]);
    	}
    	return 0;
    }
    

    KMP:

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int maxn=200005;
    char A[maxn],B[maxn];
    int N,M,Q,cnt[maxn],nxt[maxn],f[maxn];
    int main()
    {
    #ifdef local
    	freopen("pro.in","r",stdin);
    #endif
    	scanf("%d%d%d",&N,&M,&Q);
    	scanf("%s%s",A+1,B+1);
    	nxt[1]=0;
    	for(int i=2,j=0;i<=M;i++)
    	{
    		while(j&&B[i]!=B[j+1]) j=nxt[j];
    		if(B[i]==B[j+1]) j++;
    		nxt[i]=j;
    	}
    	for(int i=1,j=0;i<=N;i++)
    	{
    		while(j&&(j==M||A[i]!=B[j+1])) j=nxt[j];
    		if(A[i]==B[j+1]) j++;
    		f[i]=j;
    	}
    	for(int i=1;i<=N;i++) cnt[f[i]]++;
    	for(int i=M;i>=1;i--) cnt[nxt[i]]+=cnt[i];
    	while(Q-->0)
    	{
    		int x; scanf("%d",&x);
    		printf("%d
    ",cnt[x]-cnt[x+1]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    vue-router的push和replace的区别
    ajax请求常见状态码以及产生的原因
    vue定义data的三种方式与区别
    button与input button区别
    变量的声明方式
    js变量
    JavaScript的节流与防抖?
    js实现继承的方法-构造函数
    前端表单验证常用的15个JS正则表达式
    ES6中的新增数组的方法
  • 原文地址:https://www.cnblogs.com/happyZYM/p/11379157.html
Copyright © 2020-2023  润新知