码迷,mamicode.com
首页 > 其他好文 > 详细

Power Strings

时间:2018-10-11 01:37:23      阅读:172      评论:0      收藏:0      [点我收藏+]

标签:遇到   为什么   传送门   turn   getch   utc   har   线性   printf   

传送门

这道题的大意是让我们求出一个字符串内的最小循环节,然后输出这个循环节在字符串中出现过的次数。

如何求呢?一开始我有一种极为暴力的思想,就是每次暴力匹配,遇到一个不匹配的就把它压入当前串,从下一位继续开始匹配。

然而这样会被卡……比如说qaqqaqqaq,程序会输出1,而正确的答案是3.

那么怎么办呢……?我们思考一下之后发现,如果首先用kmp预处理出 整个字符串的next数组的话,那么n-next[n]的大小就是最小循环节的大小。不过还没完,如果它能被n整除则是,否则的话最小循环节就是字符串本身。

为什么呢?因为next[i]表示i之前最长的公共前后缀长度,那么i-next[i]这么一段肯定也是后缀的一个前缀,而这个前缀也同样出现在了上面的字符串中,所以它必然是循环节,而且就是最小的循环节,否则的话那么next[i]其实是可以变得更长的。

这个好像不画图难以讲懂……我们借鉴一下Ssy的讲解吧!(毕竟人家博客好看图画的好讲的好!)传送门

所以这样我们直接线性跑一遍就可以过了。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<set>
#include<queue>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar(‘\n‘)

using namespace std;
typedef long long ll;
const int M = 10005;
const int N = 1000005;
const int INF = 1000000009;

int read()
{
    int ans = 0,op = 1;
    char ch = getchar();
    while(ch < 0 || ch > 9)
    {
    if(ch == -) op = -1;
    ch = getchar();
    }
    while(ch >= 0 && ch <= 9)
    {
    ans *= 10;
    ans += ch - 0;
    ch = getchar();
    }
    return ans * op;
}

int n,cur,last,nxt[N];
char s[N],t[N];

void getnext()
{
    int j = 0;
    rep(i,2,n)
    {
    while(j && s[j+1] != s[i]) j = nxt[j];
    if(s[j+1] == s[i]) j++;
    nxt[i] = j;
    }
}

int main()
{
    while(1)
    {
    scanf("%s",s+1),n = strlen(s+1);
    if(s[1] == .) break;
    getnext();
    //rep(i,1,n) printf("%d ",nxt[n]);
    n%(n-nxt[n]) ? printf("1\n") : printf("%d\n",n / (n-nxt[n]));
    }
    return 0;
}

 

Power Strings

标签:遇到   为什么   传送门   turn   getch   utc   har   线性   printf   

原文地址:https://www.cnblogs.com/captain1/p/9769953.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!