zoukankan      html  css  js  c++  java
  • LOJ#10045. 「一本通 2.2 练习 1」Radio Transmission

    UPD:更新了一种推导方法,但原推导方法没有删除。

    为下文表述方便,这里做出一些约定:

    1. 字符串下标从 (1) 开始
    2. (l) 代表题目给定字符串 (s) 的长度;
    3. (operatorname{next}) 代表 KMP 算法的失配函数,(operatorname{next}(i)) 表示 (s_{1dots i}) 的最长公共前缀后缀的长度;
    4. 对于两个字符串 (s_1,s_2)(s_1+s_2) 代表将两个字符串拼接起来,如 (mathtt{abc}+mathtt{defg}=mathtt{abcdefg})

    题目传送门

    推导方法一:

    令最短循环节为 (s_1),字符串结尾残缺的一段循环节为 (s_2)(s_2) 变成循环节需要补上的串为 (s_3)。根据定义,可得 (s_1=s_2+s_3)

    有了上面的定义,这道题给出的字符串 (s) 就可以表示为 (s_1,s_1,dots,s_1,s_2) 的形式。将 (s) 中的所有 (s_1) 拆成 (s_2)(s_3),此时 (s=s_2,s_3,s_2,s_3,cdots,s_2,s_3,s_2)

    通过这一些列拆分,我们很容易得出 (s) 的最长公共前缀后缀:( lap{overbrace{phantom{s_2,s_3,s_2,s_3,cdots,s_2}}^{ ext{prefix}}}s_2,s_3,underbrace{s_2,s_3,cdots,s_2,s_3,s_2}_{ ext{suffix}})

    观察发现当 (s) 扔掉后缀(suffix)后,剩下 (s_2)(s_3),放在一起就是 (s_1),也就是我们要求的循环节。

    综上,最短循环节长度为 (l-operatorname{next}(l))


    推导方法二:

    请确保用 KMP 算法做完 POJ2406 了之后再读这个推导方法。

    从 POJ2406 这道题,我们知道:对于一个长度为 (l) 的字符串 (s)(假设它的下标从 (1) 开始),它的最短循环节长度是 (l-operatorname{next}(l))

    虽然这道题的字符串是不完整的,但上面的结论仍然成立。下面我们来推导一下为什么:

    (s=mathtt{abcabcabc}),这时 (s_{1dots 6}=s_{4dots 9})(operatorname{next}(9)=6)
    去掉 (s) 的最后一个字符 (mathtt c),此时 (s=mathtt{abcabcab})(s_{1dots 5}=s_{4dots 8})(operatorname{next}(8)=5)
    再去掉 (s) 的最后一个字符 (b),此时 (s=mathtt{abcabca})(s_{1dots 4}=s_{4dots 7})(operatorname{next}(7)=4)

    发现什么规律了吗?每当我们将 (s) 的长度减一,(operatorname{next}(l)) 也会随着减一,(l-operatorname{next}(l)) 一直不变,算出的一直是完整字符串的答案。

    配合着图再仔细理解一下:

    至于 (operatorname{next}(l)) 为什么会随着长度递减,多看看这张图大概就理解了……

    说了这么多,来看看这道题的完整代码:(其实核心代码只有一行qaq)

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int N=1e6;
    char s[N+10];
    int nxt[N+10],n;
    void init()
    {
    	memset(nxt,0,sizeof(nxt));
    	int n=strlen(s);
    	for(int i=1;i<n;i++)
    	{
    		int j=nxt[i-1];
    		while(j && s[i]!=s[j]) j=nxt[j-1];
    		if(s[i]==s[j]) j++;
    		nxt[i]=j;
    	}
    }
    int main()
    {
    	scanf("%d%s",&n,s);
    	init();
    	printf("%d
    ",n-nxt[n-1]);
    	return 0;
    }
    
  • 相关阅读:
    EventBus详解
    Java BigDecimal使用
    StringFormate使用
    Sourcetree拉取推送问题
    Android下拉刷新控件android-Ultra-Pull-To-Refresh 使用
    SourceTree跳过Atlassian账号,免登陆,跳过初始设置
    Android Studio3.2新建项目gradle read time out
    底部导航栏使用BottomNavigationBar
    PopupWindow封装
    电脑连接真机,但是androidstudio不显示手机,ADB Interface黄色感叹号
  • 原文地址:https://www.cnblogs.com/juruo-zzt/p/13325195.html
Copyright © 2011-2022 走看看