首页 > 其他分享 >洛谷题单指南-字符串-P2375 [NOI2014] 动物园

洛谷题单指南-字符串-P2375 [NOI2014] 动物园

时间:2024-10-17 10:37:33浏览次数:10  
标签:子串 Cnt 后缀 P2375 洛谷题 ++ Next NOI2014 int

原题链接:https://www.luogu.com.cn/problem/P2375

题意解读:计算字符串所有子串的不重叠相同前后缀数量。

解题思路:

1、KMP+暴力

通过Next数组,可以计算所有子串相同前后缀的数量

然后枚举Next数组,通过回跳Next[j]、Next[Next[j]-1]、Next[Next[Next[j]-1] - 1]......来统计长度小于子串长度一半的前后缀个数,记录在num[]数组

50分代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 1000005, MOD = 1e9 + 7;
int n;
string s;
int Next[N], num[N];
long long ans = 1;

int main()
{
    cin >> n;
    while(n--)
    {
        memset(Next, 0, sizeof(Next));
        memset(num, 0, sizeof(num));
        cin >> s;
        ans = 1;
        //计算每个子串的最长相同前后缀长度,标准Next数组
        for(int i = 1, j = 0; i < s.size(); i++)
        {
            while(j && s[i] != s[j]) j = Next[j - 1];
            if(s[i] == s[j]) j++;
            Next[i] = j;
        }
        //统计每个子串前后缀不重叠的数量
        for(int i = 0; i < s.size(); i++)
        {
            int j = Next[i];
            while(j)
            {
                if(j * 2 <= i + 1) num[i]++;
                j = Next[j - 1];
            } 
        }
        //计算答案
        for(int i = 0; i < s.size(); i++)
        {
            ans = ans * (num[i] + 1) % MOD;
        }
        cout << ans << endl;
    }
    return 0;
}

2、KMP+递推

由于枚举找到长度小于子串一半的前后缀复杂度整体是O(n^2),需要进行优化

设Cnt[i]表示0~i子串的相同前后缀数量,根据定义可知cnt[i] = 0~Next[i]-1的相同前后缀数量 + 1,即Cnt[i] = Cnt[Next[i]-1] + 1

那么在计算Next的过程中,可以同时将Cnt[]通过递推计算出来。

for(int i = 1, j = 0; i < s.size(); i++)
{
    while(j && s[i] != s[j]) j = Next[j - 1];
    if(s[i] == s[j]) j++;
    Next[i] = j;
    if(j) Cnt[i] = Cnt[j - 1] + 1; //0~i的相同前后缀数量 = 0~Next[i]-1的相同前后缀数量 + 1
}

然后再进行一次Next计算过程,当找到一组前后缀匹配时,判断长度是否超过子串一半,一直往前跳到长度小于等于子串长度一半,此时Num[i]就是当前前后缀的长度j + Num[j-1]

for(int i = 1, j = 0; i < s.size(); i++)
{
    while(j && s[i] != s[j]) j = Next[j - 1];
    if(s[i] == s[j]) j++;
    while(j * 2 > i + 1) j = Next[j - 1]; //当前后缀长度超过子串一半时,不断缩减直到找到不超过子串一半的前后缀长度
    if(j) Num[i] = Cnt[j - 1] + 1; //0-i的不重叠相同前后缀数量 = 长度j的前后缀 + 0~j-1的相同前后缀数量
}

100分代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 1000005, MOD = 1e9 + 7;
int n;
string s;
int Next[N], Cnt[N], Num[N]; //Cnt[i]表示0~i子串中相同前后缀的数量
long long ans = 1;

int main()
{
    cin >> n;
    while(n--)
    {
        memset(Next, 0, sizeof(Next));
        memset(Cnt, 0, sizeof(Cnt));
        memset(Num, 0, sizeof(Num));
        cin >> s;
        ans = 1;
        //计算每个子串的最长相同前后缀长度,标准Next数组
        for(int i = 1, j = 0; i < s.size(); i++)
        {
            while(j && s[i] != s[j]) j = Next[j - 1];
            if(s[i] == s[j]) j++;
            Next[i] = j;
            if(j) Cnt[i] = Cnt[j - 1] + 1; //0~i的相同前后缀数量 = 0~Next[i]-1的相同前后缀数量 + 1
        }
        //统计每个子串前后缀不重叠的数量
        for(int i = 1, j = 0; i < s.size(); i++)
        {
            while(j && s[i] != s[j]) j = Next[j - 1];
            if(s[i] == s[j]) j++;
            while(j * 2 > i + 1) j = Next[j - 1]; //当前后缀长度超过子串一半时,不断缩减直到找到不超过子串一半的前后缀长度
            if(j) Num[i] = Cnt[j - 1] + 1; //0-i的不重叠相同前后缀数量 = 长度j的前后缀 + 0~j-1的相同前后缀数量
        }
        //计算答案
        for(int i = 0; i < s.size(); i++)
        {
            ans = ans * (Num[i] + 1) % MOD;
        }
        cout << ans << endl;
    }
    return 0;
}

 

标签:子串,Cnt,后缀,P2375,洛谷题,++,Next,NOI2014,int
From: https://www.cnblogs.com/jcwy/p/18471376

相关文章

  • 洛谷题单指南-字符串-P3435 [POI2006] OKR-Periods of Words
    原题链接:https://www.luogu.com.cn/problem/P3435题意解读:定义字符串a是b的周期,当a是b的真前缀,且b是aa的前缀。给定字符串s,求s每一个前缀的最大周期长度之和。解题思路:针对字符串babababa进行样例模拟:前缀子串  最大周期  周期长度b空0ba空0babba2......
  • 洛谷题单指南-字符串-Test
    原题链接:https://www.luogu.com.cn/problem/CF25E https://codeforces.com/contest/25/problem/E题意解读:给定a,b,c三个字符串,求包含a、b、c的最短字符串长度。解题思路:要得到包含a、b、c的字符串,可以通过a、b、c连接形成,而要使得连接后的字符串最短,可以尽可能的利用重叠部分......
  • 洛谷题单指南-字符串-P1470 [USACO2.3] 最长前缀 Longest Prefix
    原题链接:https://www.luogu.com.cn/problem/P1470题意解读:求s最长前缀长度,使得可以拆解成p集合中的字符串解题思路:动态规划:设s字符串下标从1开始,p集合用set<string>保存所有的元素状态表示:设f[i]表示前i个字符s[0~i-1]是否能拆解成p中的元素状态计算:对于j=i-1开始往后倒......
  • [NOI2014] 动物园——KMP 倍增
    [NOI2014]动物园题目描述近日,园长发现动物园中好吃懒做的动物越来越多了。例如企鹅,只会卖萌向游客要吃的。为了整治动物园的不良风气,让动物们凭自己的真才实学向游客要吃的,园长决定开设算法班,让动物们学习算法。某天,园长给动物们讲解KMP算法。园长:“对于一个字符串\(S\),它......
  • 洛谷题单指南-字符串-P5283 [十二省联考 2019] 异或粽子
    原题链接:https://www.luogu.com.cn/problem/P5283题意解读:n个整数,每次从从取l~r的数进行异或得到美味值,一共取k次,并计算这k个美味值之和的最大值。解题思路:1、如何O(1)的计算l~r数的异或,得到美味值可以借助前缀和思想,a[i]为第i个数,s[i]表示a[1]~a[i]每个数的异或值,要计算l~r的......
  • E65 树形DP P3237 [HNOI2014] 米特运输
    视频链接:E65树形DPP3237[HNOI2014]米特运输_哔哩哔哩_bilibili  P3237[HNOI2014]米特运输-洛谷|计算机科学教育新生态(luogu.com.cn)//树形DPO(n)#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;constintN=500005,mod=1e9+7;......
  • 洛谷题单指南-字符串-P2580 于是他错误的点名开始了
    原题链接:https://www.luogu.com.cn/problem/P2580题意解读:给n个字符串,再依次处理m个字符串,对于每个字符串,如果在前面n个字符串中输出OK,如果不在n个字符串中输出WRONG,如果在n个字符串中且不止一次查询过输出REPEAT。解题思路:1、set/map方法很简单直接,用set存下前n个字符串,map......
  • 洛谷题单指南-字符串-P1481 魔族密码
    原题链接:https://www.luogu.com.cn/problem/P1481题意解读:在n个字符串中找到最长的词链长度,定义字符串a、b、c可以形成词链,即a是b的前缀、b是c的前缀。解题思路:1、Trie树定义Trie树,也称前缀树、字典树,核心思想是将字符串拆解为单个字符,每个字符是树的一条边,节点是字符添加到树......
  • 洛谷题单指南-字符串-P4391 [BOI2009] Radio Transmission 无线传输
    原题链接:https://www.luogu.com.cn/problem/P4391题意解读:s1由若干个s2组成,求s2的最小长度,注意题目中说明s1是子串,但是不影响,可以认为s1是补全的由若干s2组成的字符串。解题思路:设s1由x个s2组成,如图所示设s1的Next数组从0开始,那么其最长相同前后缀长度为x-1个s2,即Next[s1.siz......
  • 洛谷题单指南-字符串-P3375 【模板】KMP
    原题链接:https://www.luogu.com.cn/problem/P3375题意解读:给定两个字符串:原串s,模式串p,求p在s中出现的所有位置,并输出p的长度为1~p.size()的子串的最长相同真前、后缀的长度。解题思路:KMP模版题,分两问,第一问通过KMP核心算法实现,第二问输出模式串的Next数组内容,接下来一一解读。......