kmp

最小表示算法。。。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cmath>
using namespace std;
const int maxlen=1e6+5;
template<typename T>
inline void read(T &a){
    a=0;T b=1;char x=getchar();
    while(x<'0'||'9'<x){
        if(x=='-')b=-1;
        x=getchar();
    }
    while('0'<=x&&x<='9'){
        a=(a<<1)+(a<<3)+x-'0';
        x=getchar();
    }
    a*=b;
}
char ch[50];
int temp;
template<typename T>
inline void print(T a){
    if(a<0){
        putchar('-');
        a=-a;
    }
    do{
        ch[++temp]=a%10+'0';
        a/=10;
    }while(a);
    while(temp)putchar(ch[temp--]);
}
char s[maxlen];
int next[maxlen],len;
inline void kmp_init(){
    int p=0;
    for(int i=2;i<=len;i++){
        while(s[p+1]!=s[i] && p)p=next[p];
        if(s[p+1]==s[i])p++;
        next[i]=p;
    }
}
int kmp(int p){
//递归求解最小表示长度 奇数个or偶数个 
    if(!next[p])return p;
    
    if(next[p]*2==p){
        return kmp(next[p]);
    }
    else if( !(p%(p-next[p]*2)) ){
        int ans=kmp(p-next[p]);
        return !(p%ans) ? ans : p;
    }
    else return p;
}
inline int judge(int pp){
    int ans=0,p=0,last=0;
    for(int i=1;i<=len;i++){
        while(s[p+1]!=s[i]&&p)p=next[p];
        if(s[p+1]==s[i])p++;
        
        if(i-p!=last)break;
        
        if(p==pp){
            ans++;
            p=next[p];
            last=i;
        }
    }
    return ans;
}
int main(){
    while(gets(s+1)!=NULL){
        memset(next,0,sizeof(next));
        len=strlen(s+1);
        kmp_init();
        
        if(next[len]){
            if(len%(len-next[len])==0)print(len/(len-next[len]));
//告诉我们一个道理:next[i]不一定<(i/2),瞬间变得简单了
else print(1); } else print(1); putchar('\n'); } return 0; }

zoo:

分析一下,为什么一直TLE,没有想到o(n)算法,自己也是加了好多优化

由于自己没有把next数组用上,kmp在 初始化 时&&匹配 时使用next数组,

自己只在初始化用了,匹配没用,而且一直想怎么快点暴力而不是换个角度,

分析结束。!!!把一个问题想到非常清晰再写,包括复杂度,具体流程!!!

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cmath> 
#define LL long long 
using namespace std;
const int P=1000000007;
const int maxn=1e6+5;
int n,len,next[maxn];
LL ans;
char s[maxn];
inline void kmp_init(){
    len=strlen(s+1);
    ans=1ll;
    
    int p=0;
    for(int i=2;i<=len;i++){
        while(s[p+1]!=s[i]&&p)p=next[p];
        if(s[p+1]==s[i])p++;
        next[i]=p;
    }
}
int main(){
    scanf("%d",&n);
    while(n--){
        
        scanf("%s",s+1);
        kmp_init();
        for(int i=1;i<=len;i++){
            int j=next[i];
            LL now=0;
            while(j){
                if(j%(j-next[j])==0){//可以最小表示 
                    int l=j-next[j];//循环串长度 
                    now+=min(j/l,i/2/l);
                    break;
                }
                if(j*2<=i)now++;
                j=next[j];
            }
            //printf("%d ",now);
            ans=ans*(now+1)%P;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

 kmp其实有一步是自己和自己匹配,所以

可以考虑 自己匹配自己 而不是直接暴跳next数组

std:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define LL long long
using namespace std;
template <typename T>
inline void read(T &a){
    a=0;T b=1;char x=getchar();
    while(x<'0'||'9'<x){
        if(x=='-')b=-1;
        x=getchar();
    }
    while('0'<=x&&x<='9'){
        a=(a<<1)+(a<<3)+x-'0';
        x=getchar();
    }
    a*=b;
}
char ch[50];
int Temp;
template<typename T >
inline void print(T a){
    if(a<0){
        putchar('-');
        a=-a;
    }
    do{
        ch[++Temp]=a%10+'0';
        a/=10;
    }while(a);
    while(Temp)putchar(ch[Temp--]);
}
const int maxlen=1e6+5;
const LL P=1000000007;
int n,len,next[maxlen];
LL deep[maxlen];
char a[maxlen];
inline void kmp_init(){
    //memset(next,0,sizeof(next));
    //memset(deep,0,sizeof(deep));
    len=strlen(a+1);
    int p=0;//next[1]=0;
    deep[1]=1ll;
    for(int i=2;i<=len;i++){
        while(p&&a[p+1]!=a[i])p=next[p];
        if(a[p+1]==a[i])p++;
        next[i]=p;
        //print(next[i]);print(i);putchar('\n');
        deep[i]=deep[p]+1;
        //deep[i]表示i位置能回跳的步数 
    }
}
LL ans;
int main(){
    read(n);
    while(n--){
        scanf("%s",a+1);
        kmp_init();
        ans=1;
        int p=0;
        for(int i=2;i<=len;i++){
            while(p&&a[p+1]!=a[i])p=next[p];
            //记得kmp就是自己和自己(别人)匹配的过程 
            
            if(a[p+1]==a[i])p++;
            while((p<<1)>i)p=next[p];
            ans=(ans*(deep[p]+1))%P;
        }
        print(ans);putchar('\n');
    }
    return 0;
}

 

posted @ 2019-06-05 19:52  Tj1  阅读(133)  评论(0编辑  收藏  举报