• 【bzoj3620】似乎在梦中见过的样子 KMP


    题目描述

    给出一个长度$le 15000$的字符串,求满足形似于$A+B+A$($len(A)ge k,len(B)ge 1$)的子串数量。

    输入

    第一行一个字符串,第二行一个数 k

    输出

    仅一行一个数 ans,表示 QB 以及它的替身的数量

    样例输入

    aaaaa
    1

    样例输出

    6


    题解

    KMP

    竟然还有$n^2$过15000的题。。。

    由于$len(A)$的限制是$le k$,而$len(B)$的限制是$le 1$。因此对于一个子串,找出满足$len(B)ge 1$条件的$len$最大的$A$。

    即找出$len(A)*2<L$的最长的公共前后缀A。

    枚举子串的左端点的话,问题就和 动物园 类似,但是需要线性做法,于是特意学了一下那道题的正解。

    求next数组的过程相同,在求next的同时直接处理出满足条件的最长前驱后继。具体方法与求next相同,维护一个上一位置的指针,当不满足下一个字符相同,或当长度大于等于一半时k=next[k]即可。最坏总时间复杂度也是$O(L)$的。

    求出以后判断最大长度是否大于$k$即可。

    时间复杂度为$O(n^2)$,由于常数小可以通过。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    char s[15010];
    int next[15010] , p;
    int calc(char *s , int n)
    {
    	int i , j , k , ans = 0;
    	next[0] = -1;
    	for(i = 1 , j = k = -1 ; i <= n ; i ++ )
    	{
    		while(~j && s[j] != s[i - 1]) j = next[j];
    		next[i] = ++j;
    		while(~k && (s[k] != s[i - 1] || (k + 1) << 1 >= i)) k = next[k];
    		if(++k >= p) ans ++ ;
    	}
    	return ans;
    }
    int main()
    {
    	int n , i , ans = 0;
    	scanf("%s%d" , s , &p) , n = strlen(s);
    	for(i = 0 ; i < n ; i ++ ) ans += calc(s + i , n - i);
    	printf("%d
    " , ans);
    	return 0;
    }
    

     

  • 相关阅读:
    Minimum Inversion Number(归并排序)
    Ultra-QuickSort(归并排序)
    求逆序数(归并排序)
    Hat's Fibonacci(大数,好)
    Baskets of Gold Coins
    Permutation Recovery(模拟)
    反恐训练营(LCS)
    I Hate It(线段树)
    敌兵布阵
    Django报错:提交表单报错---RuntimeError: You called this URL via POST, but the URL doesn’t end in a slash and you have APPEND_SLASH set.
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7600211.html
Copyright © 2020-2023  润新知