当前位置: 首页 > news >正文

[POI2006] OKR-Periods of Words——最大周期长度(扩展最小周期长度)

[POI2006] OKR-Periods of Words——最大周期长度(扩展最小周期长度)

[原题链接](P3435 [POI2006] OKR-Periods of Words - 洛谷 | 计算机科学教育新生态 (luogu.com.cn))


字符串的周期

讲这道题之前,我们先聊一聊字符串的周期。我们要明确周期border两个概念

周期

对字符串 s s s 0 < p ≤ ∣ s ∣ 0<p\leq \left|s \right| 0<ps,若 s [ i ] = s [ i + p ] s[i]=s[i+p] s[i]=s[i+p]对所有 i ∈ [ 0 , ≤ ∣ s ∣ − p − 1 ] i \in [0,\leq \left|s \right| -p-1] i[0,sp1] 成立,则称 p p p s s s的周期

border

对字符串 s s s 0 < p < ∣ s ∣ 0<p< \left|s \right| 0<p<s,若s长度为r的前缀和长度为r的后缀相等,就称s长度为r的前缀是s的border

由s由长度为r的border可以推导出 ≤ ∣ s ∣ − r \leq \left|s \right|-r sr是s的周期

根据kmp的next数组,可以得到s(下标从0开始)的所有border长度,next[n-1],next[next[n-1]-1],…

显然s的最小周期 n − n e x t [ n − 1 ] n-next[n-1] nnext[n1]

思路

现在我们回到该题:

该题就是让我们求字符串 s 1 s_1 s1的最小周期

代码

代码如下

#include <bits/stdc++.h>

using namespace std;

const int N = 1e6 + 10;

char c[N];
int ne[N];

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n;
    // 字符串下标从1开始
    cin >> n >> c + 1;
    // 获取next数组
    for (int i = 2, j = 0; i <= n; i ++) {
        while (j && c[i] != c[j + 1])
            j = ne[j];
        if (c[i] == c[j + 1]) {
            j ++;
            ne[i] = j;
        }
    }
    cout << n - ne[n];

    return 0;
}

扩展:最大周期长度

让每一个next数组的值都是最短前缀

核心代码

int j = n;
// 转换为最短前缀
while (ne[j]) 
    j = ne[j];
// 记忆化存储
if (ne[i])  ne[i] = j;
// 最大周期长度
len = n - j;

例题

[[POI2006] OKR-Periods of Words](P3435 [POI2006] OKR-Periods of Words - 洛谷 | 计算机科学教育新生态 (luogu.com.cn))

分析

求每个子串的最大周期长度

样例分析

bab 2

baba 2

babab 4

bababa 4

bababab 6

babababa 6

参考代码

#include <iostream>

using namespace std;

const int N = 1e6 + 10;
typedef long long LL;

char s[N];
LL ne[N];

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    int n;
    cin >> n >> s + 1;
    for (int i = 2, j = 0; i <= n; i ++) {
        while (j && s[i] != s[j + 1])
            j = ne[j];
        if (s[i] == s[j+1])
            j ++;
        ne[i] = j;
    }
    LL ans = 0;
    for (int i = 2; i <= n; i ++) {
        int j = i;
        while (ne[j]) {
            j = ne[j];
        }
        if (ne[i])  ne[i] = j;
        ans += i-j;
    }
    cout << ans << endl;

    return 0;
}

相关文章:

  • OpenCV中更稳更快的边缘检测方法,快速查找线、圆、椭圆--EdgeDrawing-C++代码
  • 推导式
  • Linux---(五)三大工具yum、vim、gcc/g++
  • 有符号数是如何判断正负符号位的?
  • 基于element-plus定义表格行内编辑配置化
  • fpga时序相关概念与理解
  • Pydantic:数据类型确认和解析神器
  • 3.0.3版vsftpd所支持的FTP命令
  • 【Docker】iptables基本原理
  • 基于51单片机的万年历-脉搏计仿真及源程序
  • 【面经】ES中分片是什么?副本是什么?
  • 《DevChat:AI编程助手引领开发新潮》
  • 创建一个事务级临时表或者会话级临时表继续测试,在什么情况下临时表里的数据会消失
  • Android---App 崩溃
  • 一个用python PyQT写的背单词小程序
  • 快速部署OpenStack全新UI管理Skyline Dashboard
  • 引用(类名后加符号)和指针的区别
  • 数据分析实战 | 线性回归——女性身高与体重数据分析
  • Go采集代理框架
  • 使用IDEA让文本对比不在变的困难
  • 经济日报金观平:促进信贷资金畅达小微企业
  • 国宝归来!子弹库帛书二、三卷抵达北京
  • 纪念|脖子上挂着红领巾的陈逸飞
  • 上百家单位展示AI+教育的实践与成果,上海教育博览会开幕
  • 六省会共建交通枢纽集群,中部离经济“第五极”有多远?
  • 普京批准俄方与乌克兰谈判代表团人员名单