51nod 1554 KMP思维题

题目为中文,因而不再解释题意。

首先遵循如下设定可以有以下几个结论:
1,首先谈论下KMP的一个特殊性质:对于某一个特立独行的字符串:例如ABCDEF,在建立有限状态自动机之后,都会有,所有元素的失配边,指向0,也就是初始的那个元素。此时我们可以讲这个独立的元素及之前字符串理解为“ 一个循环次数为1的循环串 ”。对于其他情况,形如:ABCDEFGAB,可以将ABCDEFG理解为一个循环串,AB为下一个循环的两个多余元素,因此,我们可以把任意字符串看成“ 一个循环串+若干独立元素 ”的巧妙形式。

2,对于该形式,都可以发现,对于第K号元素最小循环节的尺寸应当为“ K-F[K] ”(随着规约不同增减1,此处采用刘汝佳蓝书中KMP的规约),那么,我们可以在这个基础上求出来“最小循环节”循环的次数——K/(K-F[K])。

3,应当认为,任意一个串,都构成(AB)*N+A的的形式。区别仅仅在于N的取值

4,应当认为,任何一个循环串,形如(A+B)*N,都自然的可以被认为是(A+B+A+B)*N+(A+B)*k的形式,即可以将若干个相同的循环节看成一个大的循环节。

5,前文中,我们知道了,“如何求出循环串的最小循环节”,以及“最小循环节的长度”,从而可以求出“最小循环节出现的次数”。则对于给定目标m来说,很容易求出,满足有且仅有M个大循环节时,每个大循环节的 “  最小循环体数量    ”,同时,也可以求出来,在满足上述条件后,“ 剩余的循环体数量 ”容易理解,在任何情况下,剩余的循环体数量大于最小循环体数量则构成一个新的循环,意味着M+1明显不符合题设,应当直接排出。

 

回过头来发现刘汝佳蓝书第一道练习例题就讲的是这个233333333333

 

放AC代码如下:

#include<bits/stdc++.h>
using namespace std;

const long long MAXN=1000233;

char tar[MAXN];
long long f[MAXN];

long long n,m;
void init()
{
    cin>>n>>m;
    cin>>tar;
    
    f[1]=0;f[0]=0;
    for(int i=1;i<n;++i)
    {
        int j=f[i];
        while(j&&tar[i]!=tar[j])j=f[j];
        f[i+1]= tar[i]==tar[j]? j+1:0;
    }
}


int main()
{
    cin.sync_with_stdio(false);
    init();
    for(int i=1;i<=n;++i)
    {
        int val=i/(i-f[i]);
        if(i%(i-f[i]))
        {
            if(val/m>val%m)cout<<1;
            else cout<<0;
        }else 
        {
            if(val/m>=val%m)cout<<1;
            else cout<<0;
        }
    }
    
    return 0;
}

 

posted @ 2017-08-23 12:20  六花的邪王真眼  阅读(262)  评论(0编辑  收藏  举报