标签:遇到 为什么 传送门 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; }
标签:遇到 为什么 传送门 turn getch utc har 线性 printf
原文地址:https://www.cnblogs.com/captain1/p/9769953.html