修仙 (KMP)

来源:互联网 发布:java开发项目案例 编辑:程序博客网 时间:2024/06/08 05:45

修仙

10.25

前100%的数据:看样子就是道KMP的题对吧。仔细想想KMP的性质,fail[i]则说明s[1,fail[i]]=s[i-fail[i]+1,i],说明这个前缀在(i-1fail[i]+1,i)出现过,实际上我们只用考虑长度,因为同一个长度对应的前缀相同。于是对于2<=i<=n-1,标记一下fail[i]这个长度出现过(既是前缀又是中缀)。再从n开始不停跳fail,直到跳到一个位置t(既是前缀又是后缀),满足t这个长度出现过,输出t即可。

然而实际上,稍加分析就可以得到,这道题用hash暴力是几乎被卡不掉的,这可以通过之前所讲的循环节知识来证明。所以空间被卡了吧,嘿嘿嘿。不过还是良心地没有卡正解的空间,虽然标程使用了bitset压位,但是直接用bool数组存长度是否出现过也是能够通过的。

当然要是还是被水过去了,各位还是一定一定要认真思考这道题的正解,这是KMP的一项基础而十分重要的性质。

神**卡内存,size算出来83,然后运行的时候就GG了,要卡空间的话vis数组变成个bool,只记录是否出现过,然后再O(n)扫一遍就好了。

#include <iostream>#include <cstdio>#include <cstring>using namespace std;const int N = 10000005;int nxt[N], vis[N];char s[N];int len;void calcnext() {    int i = 0, j = -1;    nxt[0] = -1;    while(i < len) {        if(j == -1 || s[i] == s[j]) {            i++, j++;            nxt[i] = j;            vis[j]++;        }        else            j = nxt[j];    }}int main(){    freopen ("hhh.in", "r", stdin);    freopen ("hhh.out", "w", stdout);    //cout << ( sizeof(nxt) + sizeof(s) + sizeof(vis) ) / 1024 / 1024 << endl;    scanf("%s", s);    len = strlen(s);    calcnext();    int cc = nxt[len];    if(vis[cc] > 1) printf("%d\n", cc);    else printf("%d\n", nxt[cc]);    return 0;}