zoukankan      html  css  js  c++  java
  • 【题解】洛谷P2375 [NOI2014] 动物园(KMP)

    洛谷P2375:https://www.luogu.org/problemnew/show/P2375

    思路

    这道题可以说是完全刷新了本蒟蒻对KMP的理解

    感觉对next数组的理解上升到一个新的高度

    首先题目给出了next数组的定义

    关于整个字串 next[len]为前缀与后缀相同的最长长度

    我们给出一张从你谷题解中扒下来的图

    我们可以观察到对于整个长度为len的字串a

    next[len],next[next[len]],next[next[next[len]]]...全部都是满足前缀与后缀相同的子串

    但是仅仅把这些加起来是不足以解决这道题的

    因为题目要求的是不重叠 因此我们需要判断这个子串长度是否大于此前缀i长度的一半 我们设cnt数组为有重叠的 再从中筛选

    因为考虑到时间效率 我们需要用求next数组的方法求num数组

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    #define ll long long
    #define maxn 1000010
    #define mod 1000000007
    ll cnt[maxn],next[maxn];
    ll len,ans;
    char a[maxn];
    int T;
    void kmp()
    {
        ll j=0;
        for(ll i=2;i<=len;i++)
        {
            while(j&&a[i]!=a[j+1]) j=next[j];
            if(a[i]==a[j+1]) j++;
            next[i]=j;
            cnt[i]=cnt[j]+1;//递推公式 
        }
    }
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            memset(cnt,0,sizeof(cnt));
            memset(next,0,sizeof(next));
            ans=1;//初始化 
            scanf("%s",a+1);
            len=strlen(a+1);
            cnt[1]=1;//初始化 
            kmp();
            ll j=0;
            for(ll i=2;i<=len;i++)
            {
                while(j&&a[i]!=a[j+1]) j=next[j];
                if(a[i]==a[j+1]) j++;
                while((j<<1)>i) j=next[j];//不断缩小范围直到小于原前缀i长度的一半 
                ans*=(cnt[j]+1);//统计ans 
                ans%=mod;
            }
            printf("%lld
    ",ans);
        }
    }
    View Code
  • 相关阅读:
    当前信息型强人工智能发展缺失条件--规则
    假象篇(1)-动态可变参数的神经网络
    02梦断代码阅读笔记
    结队开发之NABCD
    01梦断代码阅读笔记
    03构建之法阅读笔记
    进度3
    02构建之法阅读笔记
    01构建之法阅读笔记
    关于最大子序和的算法问题(二)
  • 原文地址:https://www.cnblogs.com/BrokenString/p/9806559.html
Copyright © 2011-2022 走看看