• [CSP-S模拟测试]:串串香(KMP)


    题目传送门(内部题75)


    输入格式

      输入文件$ccx.in$
      每个输入文件包含多组测试数据。输入文件的第一行为一个整数$T$,表示数据组数。接下来$T$行,每行表示一组测试数据
      每行一开始,两个空格隔开的数字$n,m$,含义见【题目描述】。之后是一个长度为$m$的字符串。


    输出格式

      $T$行,每行一个整数表示答案。


    样例

    见下发文件


    数据范围与提示

      对全部测试数据,$nleqslant 10^6 ,mleqslant 10^6 ,Tleqslant 10$,输入文件中的所有$m$之和不超过$5 imes 10^6$
      第$1,2$个测试点,$m=1$
      第$3,4$个测试点,给出的字符串中只含有字母$'A'$
      第$5,6,7,8,9,10,11$个测试点,满足$n imes mleqslant 10^6$
      第$11,12,13,14,15$个测试点,满足$mleqslant 100$
      第$16,17,18,19,20$个测试点,无特殊限制


    题解

    考察对$KMP$的理解。

    一般情况下就是$(n-1) imes m$。

    话画图会发现当串长减去最长公共前后缀是串长的一个因子时答案就是$(n-1) imes m+nxt[n]$(这里的$nxt$数组其实就是$KMP$中的$nxt$数组,即为串的公共前后缀)。

    其实用$hash$也可以。

    时间复杂度:$Theta(T imessum m)$。

    期望得分:$100$分。

    实际得分:$100$分。


    代码时刻

    $KMP$:

    #include<bits/stdc++.h>
    using namespace std;
    long long n,m;
    char ch[2000001];
    int nxt[2000001];
    void KMP()
    {
    	nxt[0]=-1;
    	for(int i=0;i<m;i++)
    	{
    		int j=nxt[i];
    		while(j!=-1&&ch[i]!=ch[j])j=nxt[j];
    		nxt[i+1]=++j;
    	}
    }
    int main()
    {
    	int T;
    	scanf("%d",&T);
    	while(T--)
    	{
    		scanf("%lld%lld",&n,&m);
    		scanf("%s",ch);
    		KMP();
    		if(n==1)printf("%d
    ",nxt[m]);
    		else if(!(m%(m-nxt[m])))printf("%lld
    ",(n-1)*m+nxt[m]);
    		else printf("%lld
    ",(n-1)*m);
    	}
    	return 0;
    }

    $hash$:

    #include<bits/stdc++.h>
    using namespace std;
    long long n,m;
    char ch[1000001];
    unsigned long long mod[1000001],Hash[1000001];
    int HASH()
    {
    	mod[1]=1;
    	Hash[1]=ch[1]-'A'+1;
    	for(int i=2;i<=m;i++)
    	{
    		Hash[i]=Hash[i-1]*131+ch[i]-'A'+1;
    		mod[i]=mod[i-1]*131;
    	}
    	for(int i=m-2;i;i--)
    		if(Hash[i+1]==Hash[m]-Hash[m-i-1]*mod[i+2])return i+1;
    	return 1;
    }
    int main()
    {
    	int T;
    	scanf("%d",&T);
    	while(T--)
    	{
    		scanf("%lld%lld",&n,&m);
    		scanf("%s",ch+1);
    		int flag=HASH();
    		if(n==1)printf("%d
    ",flag);
    		else if(!(m%(m-flag)))printf("%lld
    ",(n-1)*m+flag);
    		else printf("%lld
    ",(n-1)*m);
    	}
    	return 0;
    }
    

    rp++

  • 相关阅读:
    5道趣味Python热身题【新手必学】
    操作系统特征
    二叉树的中序遍历
    英语一图画作文模板
    函数
    双阶乘与华里士公式
    因式分解
    【】连通图——详细解释
    【】this指针——c++中的特殊指针
    咱们程序员好用的云笔记
  • 原文地址:https://www.cnblogs.com/wzc521/p/11717563.html
Copyright © 2020-2023  润新知