(25+4/25+4)复健-KMP/EKMP/manache/Trie

(29/29) 3.23已完成 

1.KMP

int Next[maxn];
void prekmp(char* x,int len){
    int pre=-1,suf=0;   
    Next[0]=-1;
    while(suf<len){
        while(pre!=-1&&x[suf]!=x[pre]) pre=Next[pre];
        Next[++suf]=++pre;
    }
}
int kmp(char* x,char* y){
    int lenx=strlen(x);
    int leny=strlen(y);
    int pre=0,suf=0,ans=0;
    prekmp(x,lenx);
    while(suf<leny){
        while(pre!=-1&&y[suf]!=x[pre]) pre=Next[pre];
        pre++; suf++;
        if(pre>=lenx){
            pre=Next[pre];
            ans++;
        }
    }
    return ans;
}
模板

 

模板写法及变式(待更新)


 

基本形

其中,next数组的0号位为缺省值-1,其余位为正常位,第len位为保留位(用于处理全部匹配情况)。

next[i]存储的是对应前i-1位的最大公共前后缀长度。

一般算法理论中讨论的前后缀都是真前后缀,即不包含自身的的前后缀,为运用方便,以后统一如此编程。

next[i]=k的意义是模式串0~k-1位与i~i+k-1位相等,方便主匹配指针(指向结尾)直接通过递归方式快速滚动(j->next[j])

所以能辨别的公共词缀最小长度为2,单字不相同与单字相同无法辨别。

这是因为next数组是经过方便指针快速滚动而改造的,默认意义下的kmp算法的核心是主指针的失配而不是指针的匹配。

HDU 1711(数字序列单模式串匹配)

要求输出第一个成功匹配的位置,匹配成功直接return就好了

模板题

//#define LOCAL
#include <cstring>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <bitset>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
#define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z))
// X_INIT=0  mem_Macro
#define INF (1<<29)
#define MOD 1000000007ll
#define FOR(i,j,k) for(int i=j;i<=k;i++)
#define FORD(i,j,k) for(int i=j;i>=k;i--)
#define LL long long
#define SZ(x) int(x.size())
#define pb push_back
#define maxn 1000010
#define maxm 10010 
int a[maxn],b[maxm],Next[maxm];
int n,m,T;
inline LL read(){
    LL f=1,ans=0;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while('0'<=ch&&ch<='9'){ans=ans*10+ch-'0';ch=getchar();}
    return ans*f;
}
void doit(){
    int pre=0;
    Next[0]=0,Next[1]=0;
    FOR(suf,2,m){
        while(pre>0&&b[pre+1]!=b[suf]) pre=Next[pre];
        if(b[pre+1]==b[suf]) pre++;
        Next[suf]=pre;
    }
    return;
}
void kmp(){
    int pre=0,ans=-1;
    //Next[0]=0,Next[1]=0;
    FOR(suf,1,n){
        while(pre>0&&b[pre+1]!=a[suf]) pre=Next[pre];
        if(b[pre+1]==a[suf]) pre++;
        if(pre==m) {if(ans==-1) ans=suf-m+1; pre=Next[pre];}
    }
     cout<<ans<<endl;
    return;
}
int main(){
#ifdef LOCAL
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
cin>>T;
FOR(i,1,T){
    cin>>n>>m;
    FOR(i,1,n)
    a[i]=(int) read();
    FOR(i,1,m)
    b[i]=(int) read();
    doit();
    kmp();
}
#ifdef LOCAL
fclose(stdin);
fclose(stdout);
#endif
//system(pause);
return 0;
}
ac代码

HDU-1686(单模式串匹配)

要求输出匹配次数(可重叠)

模板题,匹配成功直接做失配处理

//#define LOCAL
#include <cstring>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <bitset>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
#define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z))
// X_INIT=0  mem_Macro
#define INF (1<<29)
#define MOD 1000000007ll
#define FOR(i,j,k) for(int i=j;i<=k;i++)
#define FORD(i,j,k) for(int i=j;i>=k;i--)
#define LL long long
#define SZ(x) int(x.size())
#define pb push_back
#define maxn 1000010
#define maxm 10010 
char a[maxn],b[maxm];
int Next[maxm];
int n,m,t;
inline LL read(){
    LL f=1,ans=0;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while('0'<=ch&&ch<='9'){ans=ans*10+ch-'0';ch=getchar();}
    return ans*f;
}
void doit(){
    int pre=0;
    Next[0]=0,Next[1]=0;
    FOR(suf,2,m){
        while(pre>0&&b[pre+1]!=b[suf]) pre=Next[pre];
        if(b[pre+1]==b[suf]) pre++;
        Next[suf]=pre;
    }
    return;
}
void kmp(){
    int pre=0,ans=0;
    FOR(suf,1,n){
        while(pre>0&&b[pre+1]!=a[suf]) pre=Next[pre];
        if(b[pre+1]==a[suf]) pre++;
        if(pre==m) {ans++;; pre=Next[pre];}
    }
     cout<<ans<<endl;
    return;
}
int main(){
#ifdef LOCAL
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
scanf("%d",&t);
FOR(i,1,t){
    scanf("%s",b+1); m=strlen(b+1);
    scanf("%s",a+1); n=strlen(a+1);
    doit();
    kmp();
} 
#ifdef LOCAL
fclose(stdin);
fclose(stdout);
#endif
//system(pause);
return 0;
}
ac代码

HDU 2087(单模式串匹配)

要求输出匹配次数(不可重叠)

模板题,以前写的是保留上次匹配的结果以检验是否可能重叠。现在看来直接将副指针归零即可

//#define LOCAL
#include <cstring>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <bitset>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
#define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z))
// X_INIT=0  mem_Macro
#define INF (1<<29)
#define MOD 1000000007ll
#define FOR(i,j,k) for(int i=j;i<=k;i++)
#define FORD(i,j,k) for(int i=j;i>=k;i--)
#define LL long long
#define SZ(x) int(x.size())
#define pb push_back
#define maxn 1000010
#define maxm 10010 
char a[maxn],b[maxm];
int Next[maxm];
int n,m,t;
inline LL read(){
    LL f=1,ans=0;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while('0'<=ch&&ch<='9'){ans=ans*10+ch-'0';ch=getchar();}
    return ans*f;
}
void doit(){
    int pre=0;
    Next[0]=0,Next[1]=0;
    FOR(suf,2,m){
        while(pre>0&&b[pre+1]!=b[suf]) pre=Next[pre];
        if(b[pre+1]==b[suf]) pre++;
        Next[suf]=pre;
    }
    return;
}
void kmp(){
    int pre=0,ans=0,spre=0;
    FOR(suf,1,n){
        while(pre>0&&b[pre+1]!=a[suf]) pre=Next[pre];
        if(b[pre+1]==a[suf]) pre++;
        if(pre==m&&suf>=spre+m) {ans++; spre=suf; pre=Next[pre];}
    }
     cout<<ans<<endl;
    return;
}
int main(){
#ifdef LOCAL
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
while(true){
    scanf("%s",a+1); if(a[1]=='#') break; n=strlen(a+1);
    scanf("%s",b+1); m=strlen(b+1);
    doit();
    kmp();
} 
#ifdef LOCAL
fclose(stdin);
fclose(stdout);
#endif
//system(pause);
return 0;
}
ac代码

HDU 1711(单模式串匹配)

要求输出第一个成功匹配的位置

模板题,练手

//#define LOCAL
#include <cstring>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <bitset>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
#define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z))
// X_INIT=0  mem_Macro
#define INF (1<<29)
#define MOD 1000000007ll
#define FOR(i,j,k) for(int i=j;i<=k;i++)
#define FORD(i,j,k) for(int i=j;i>=k;i--)
#define LL long long
#define SZ(x) int(x.size())
#define pb push_back
#define maxn 1000010
#define maxm 10010 
int a[maxn],b[maxm],Next[maxm];
int n,m,T;
inline LL read(){
    LL f=1,ans=0;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while('0'<=ch&&ch<='9'){ans=ans*10+ch-'0';ch=getchar();}
    return ans*f;
}
void doit(){
    int pre=0;
    Next[0]=0,Next[1]=0;
    FOR(suf,2,m){
        while(pre>0&&b[pre+1]!=b[suf]) pre=Next[pre];
        if(b[pre+1]==b[suf]) pre++;
        Next[suf]=pre;
    }
    return;
}
void kmp(){
    int pre=0,ans=-1;
    FOR(suf,1,n){
        while(pre>0&&b[pre+1]!=a[suf]) pre=Next[pre];
        if(b[pre+1]==a[suf]) pre++;
        if(pre==m) {if(ans==-1) ans=suf-m+1; pre=Next[pre];}
    }
     cout<<ans<<endl;
    return;
}
int main(){
#ifdef LOCAL
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
cin>>T;
FOR(i,1,T){
    cin>>n>>m;
    FOR(i,1,n)
    a[i]=(int) read();
    FOR(i,1,m)
    b[i]=(int) read();
    doit();
    kmp();
}
#ifdef LOCAL
fclose(stdin);
fclose(stdout);
#endif
//system(pause);
return 0;
}
ac代码

POJ 2752

求最大公共前后缀

//#define LOCAL
#include <cstring>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <bitset>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
#define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z))
// X_INIT=0  mem_Macro
#define INF (1<<29)
#define MOD 1000000007ll
#define FOR(i,j,k) for(int i=j;i<=k;i++)
#define FORD(i,j,k) for(int i=j;i>=k;i--)
#define LL long long
#define SZ(x) int(x.size())
#define pb push_back
#define maxn 1000010
#define maxm 1000010 
char a[maxn],b[maxm];
int Next[maxm];
int n,m,t,len;
inline LL read(){
    LL f=1,ans=0;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while('0'<=ch&&ch<='9'){ans=ans*10+ch-'0';ch=getchar();}
    return ans*f;
}
void doit(){
    int pre=0;
    Next[0]=0,Next[1]=0;
    FOR(suf,2,m){
        while(pre>0&&b[pre+1]!=b[suf]) pre=Next[pre];
        if(b[pre+1]==b[suf]) pre++;
        Next[suf]=pre;
    }
    return;
}
void kmp(){
    int pre=0,ans=0;
    //Next[0]=0,Next[1]=0;
    FOR(suf,1,n){
        while(pre>0&&b[pre+1]!=a[suf]) pre=Next[pre];
        if(b[pre+1]==a[suf]) pre++;
        if(pre==m) {ans++; pre=Next[pre];}
    }
    cout<<ans<<endl;
    return;
}
int main(){
#ifdef LOCAL
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
t=0;
stack<int> ans; 
while(scanf("%s",b+1)!=EOF){
    m=strlen(b+1);
    doit();
    while(!ans.empty()) ans.pop();
    ans.push(m);
    while(Next[m]!=0) ans.push(m=Next[m]);
    printf("%d",ans.top());ans.pop();
    while(!ans.empty()){printf(" %d",ans.top());;ans.pop();}
    cout<<endl;
} 
#ifdef LOCAL
fclose(stdin);
fclose(stdout);
#endif
//system(pause);
return 0;
}
ac代码

POJ 3080

确定多个串的最大公共子串,穷举答案即可(就用第一个字符串)

穷举答案也是字符串题常见操作了,固定起点的话记得一失配就break掉

//#define LOCAL
#include <cstring>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <bitset>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
#define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z))
// X_INIT=0  mem_Macro
#define INF 0x3f3f3f3f
#define MOD 1000000007
#define FOR(i,j,k) for(int i=j;i<k;i+=1)
#define FORD(i,j,k) for(int i=j;i>k;i-=1)
#define uLL unsigned long long
#define LL long long
#define SZ(x) int(x.size())
#define pb push_back
#define maxn 70
int Next[maxn];
int lens[maxn];
char s[maxn][maxn];
char xx[maxn];
void prekmp(char x[],int len){
    int pre=-1,suf=0;
    Next[0]=-1;
    while(suf<len){
        while(pre!=-1&&x[suf]!=x[pre]) pre=Next[pre];
        Next[++suf]=++pre;
    }
}
int kmp(int lenx,char *x,int leny,char *y){
    //int lenx=strlen(x);
    //int leny=strlen(y);
    int pre=0,suf=0,ans=0;//FOR(i,0,lenx) cout<<x[i]<<"**";
    prekmp(x,lenx);
    while(suf<leny){
        while(pre!=-1&&y[suf]!=x[pre]) pre=Next[pre];
        pre++; suf++;
        if(pre>=lenx){
            pre=Next[pre];
            ans++;
        }
    }
    return ans;
}
int main(){
#ifdef LOCAL
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
int T,n,cnt,flag,jj=0;
scanf("%d",&T);

while(T--){
    scanf("%d",&n);
    FOR(i,0,n){
        scanf("%s",s[i]);
        lens[i]=strlen(s[i]);
    }
    int len0=strlen(s[0]);
    int maxlen=-1,leni=0,lenj=0;

    FOR(i,0,len0-2){  
        cnt=-1;
        xx[++cnt]=s[0][i];
        FOR(j,i+1,len0){
            xx[++cnt]=s[0][j];
            flag=true; 
            jj=j;
            FOR(k,1,n)  if(!kmp(cnt+1,xx,lens[k],s[k])) {flag=false;break;}
            if(!flag) {jj--;break;}
        }
        if(jj-i>1){
            if(maxlen<jj-i+1) {maxlen=jj-i+1;leni=i;lenj=jj;}
            else if(maxlen==jj-i+1){
                FOR(p,0,jj-i+1) if(s[0][leni+p]>s[0][i+p]){maxlen=jj-i+1;leni=i;lenj=jj;break;}
            } 
        }
    }
    if(maxlen!=-1) FOR(p,leni,lenj+1) printf("%c",s[0][p]);
        else printf("no significant commonalities");
    if(T!=0) printf("\n");
}
//system("pause");
#ifdef LOCAL
fclose(stdin);
fclose(stdout);
#endif
return 0;
}
ac代码

hdu 2594

求S1的前缀和S2的后缀的最大匹配

建立新字符串S=S1+S2 跑个next,然后递归next[lens1+lens2],找到第一个小于lens1的next[]

//#define LOCAL
#include <cstring>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <bitset>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
#define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z))
// X_INIT=0  mem_Macro
#define INF (1<<29)
#define MOD 1000000007ll
#define FOR(i,j,k) for(int i=j;i<=k;i++)
#define FORD(i,j,k) for(int i=j;i>=k;i--)
#define LL long long
#define SZ(x) int(x.size())
#define pb push_back
#define maxn 200010
#define maxm 200010 
char a[maxn],b[maxm];
int Next[maxm];
int n,m,t,len;
inline LL read(){
    LL f=1,ans=0;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while('0'<=ch&&ch<='9'){ans=ans*10+ch-'0';ch=getchar();}
    return ans*f;
}
void doit(){
    int pre=0;
    Next[0]=0,Next[1]=0;
    FOR(suf,2,m){
        while(pre>0&&b[pre+1]!=b[suf]) pre=Next[pre];
        if(b[pre+1]==b[suf]) pre++;
        Next[suf]=pre;
    }
    return;
}
void kmp(){
    int pre=0,ans=0;
    //Next[0]=0,Next[1]=0;
    FOR(suf,1,n){
        while(pre>0&&b[pre+1]!=a[suf]) pre=Next[pre];
        if(b[pre+1]==a[suf]) pre++;
        if(pre==m) {ans++; pre=Next[pre];}
    }
    cout<<ans<<endl;
    return;
}
int main(){
#ifdef LOCAL
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
t=0;
//stack<int> ans;     
while(scanf("%s%s",b+1,a+1)!=EOF){
    m=strlen(b+1);
    n=strlen(a+1);
    FOR(i,1,n)
    b[i+m]=a[i];
    int lm=m;
    m+=n;//cout<<n;
    doit();
    if(lm==1) {if(b[1]==b[m]) printf("%c 1\n",b[1]); else printf("0\n"); }
    else if(Next[m]){ 
    while(Next[m]>lm||Next[m]>n) m=Next[m];
    FOR(i,1,Next[m])
    printf("%c",b[i]); 
    printf(" %d\n",Next[m]);
     } 
    else printf("0\n");
} 
#ifdef LOCAL
fclose(stdin);
fclose(stdout);
#endif
//system(pause);
return 0;
}
ac代码

hdu 3336

给出字符串S, 输出S所有前缀的出现次数之和

显然的,有s[0~k-1]的所有前缀的出现次数之和=s[0~next[k]]的所有前缀的出现次数之和+s[0~next[k]]这个最大的公共前后缀

为了省事直接push型dp。

不显然的,这题应该有更深的理解,remain update

//#define LOCAL
#include <cstring>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <bitset>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
#define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z))
// X_INIT=0  mem_Macro
#define INF 0x3f3f3f3f
#define MOD 1000000007
#define FOR(i,j,k) for(int i=j;i<k;i+=1)
#define FORD(i,j,k) for(int i=j;i>k;i-=1)
#define uLL unsigned long long
#define LL long long
#define SZ(x) int(x.size())
#define pb push_back
#define maxn 200010
int t,n;
char x[maxn];
int Next[maxn],f[maxn];
void prekmp(char* x,int len){
    int pre=-1,suf=0;
    Next[0]=-1;
    while(suf<=len){
        while(pre!=-1&&x[suf]!=x[pre]) pre=Next[pre];
        Next[++suf]=++pre;
    }
}
int kmp(char* x,int lenx,char* y,int leny){
    //int lenx=strlen(x);
    //int leny=strlen(y);
    int pre=0,suf=0,ans=0;
    while(suf<leny){
        while(pre!=-1&&y[suf]!=x[pre]) pre=Next[pre];
        pre++; suf++;
        if(pre>=lenx){
            pre=Next[pre];
            ans++;
        }
    }
    return ans;
}int dp[maxn];
int main(){
#ifdef LOCAL
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
scanf("%d",&t);
FOR(i,0,t){
int ans;
scanf("%d",&n);
scanf("%s",x);
memset(Next,0,sizeof(Next));
memset(dp,0,sizeof(dp));
prekmp(x,n);
dp[0]=0; ans=0;
FOR(j,1,n+1) {
    dp[j]=(dp[Next[j]]+1)%10007;
    ans+=dp[j];
    ans=ans%10007;
}
printf("%d\n",ans);
}
#ifdef LOCAL
fclose(stdin);
fclose(stdout);
#endif
return 0;
}
ac代码

hdu 1238

n个串的最大公共子串,这里的子串要求其本身匹配或者其倒转串匹配

枚举答案题的加强版,依然是善用break

//#define LOCAL
#include <cstring>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <bitset>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
#define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z))
// X_INIT=0  mem_Macro
#define INF 0x3f3f3f3f
#define MOD 1000000007
#define FOR(i,j,k) for(int i=j;i<k;i+=1)
#define FORD(i,j,k) for(int i=j;i>k;i-=1)
#define uLL unsigned long long
#define LL long long
#define SZ(x) int(x.size())
#define pb push_back
#define maxn 210
char s[4050][maxn];
char xx[maxn];
int len[maxn];
int t,ans,cnt,flag,leni,lenj;
int Next[maxn];
void prekmp(char* x,int len){
    int pre=-1,suf=0;
    Next[0]=-1;
    while(suf<len){
        while(pre!=-1&&x[suf]!=x[pre]) pre=Next[pre];
        Next[++suf]=++pre;
    }
}
int kmp(char* x,int lenx,char* y,int leny){
    //int lenx=strlen(x);
    //int leny=strlen(y);
    int pre=0,suf=0,ans=0;
    prekmp(x,lenx);
    while(suf<leny){
        while(pre!=-1&&y[suf]!=x[pre]) pre=Next[pre];
        pre++; suf++;
        if(pre>=lenx){
            pre=Next[pre];
            ans++;
        return ans;
        }
    }
    return ans;
}
int main(){
#ifdef LOCAL
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
int pp;
scanf("%d",&pp);
FOR(ppp,0,pp){
    scanf("%d",&t);
    ans=-1;
    FOR(i,0,t){
    cin>>s[i];len[i]=strlen(s[i]);}
    FOR(i,0,len[0]){
    cnt=0;
    flag=true;
    FOR(j,i,len[0]){
        xx[cnt++]=s[0][j];
            FOR(k,1,t)
            if(!kmp(xx,cnt,s[k],len[k])){
                reverse(xx,xx+cnt);
                if(!kmp(xx,cnt,s[k],len[k])) 
                {reverse(xx,xx+cnt);flag=false;break;}
                reverse(xx,xx+cnt);
            }
        if(flag) ans=max(ans,cnt-1);
    }   
    }
    printf("%d\n",ans+1);
}
//system("pause");
#ifdef LOCAL
fclose(stdin);
fclose(stdout);
#endif
return 0;
}
ac代码

反转函数reverse

虽然这玩意poj是ban掉的。。。。用法是reverse(x.begin(),x.end())。常用且善用!!!!

hdu 2328

n个串的最大公共子串,多测,数据鬼畜,愣是卡掉了我的代码,至今不知道自己怎么错的。。。

#include <cstring>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <bitset>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
const int N = 205, M = 4005;
char s[M][N], p[N], ans[N];
int  m, mx, t, k, ne[N];
void getNext() {
    ne[1] = 0;
    for (int i = 2, j = 0; i <= m; i++) {
        while (j && p[i] != p[j + 1]) j = ne[j];
        if (p[i] == p[j + 1]) j++;
        ne[i] = j;
    }
}
bool kmp(int k) {
    int n = strlen(s[k] + 1);
    getNext();
    for (int i = 1, j = 0; i <= n; i++) {
        while (j && s[k][i] != p[j + 1]) j = ne[j];
        if (s[k][i] == p[j + 1]) j++;
        if (j == m) return true;//匹配成功 
    }
    return false;
}
bool ok() {
    for (int i = 1; i <= k; i++) {
        if (!kmp(i)) return false;
    }
    return true;
} 
int main() {
    while (scanf("%d", &k), k) {
        for (int i = 1; i <= k; i++) scanf("%s", s[i] + 1); 
        //枚举所有字串
        int n = strlen(s[1] + 1); mx = 0;
        for (int i = 1; i <= n; i++) {
            for (int j = i; j <= n; j++) {
                for (int h = i; h <= j; h++) p[h - i + 1] = s[1][h]; 
                m = j - i + 1; p[m + 1] = '\0';
                if (ok()) {
                    if (m > mx) { mx = m; memcpy(ans + 1, p + 1, sizeof(p));}
                    else if(m == mx && strcmp(ans + 1, p + 1) > 0) memcpy(ans + 1, p + 1, sizeof(p));
                }  
            }
        } 
        if (!mx) printf("IDENTITY LOST\n");
        else printf("%s\n", ans + 1);
    }
    return 0;
}
ac代码

fzu 1901

求所有公共前后缀,滚一边就好了

//#define LOCAL
#include <cstring>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <bitset>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
#define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z))
// X_INIT=0  mem_Macro
#define INF 0x3f3f3f3f
#define MOD 1000000007
#define FOR(i,j,k) for(int i=j;i<k;i+=1)
#define FORD(i,j,k) for(int i=j;i>k;i-=1)
#define uLL unsigned long long
#define LL long long
#define SZ(x) int(x.size())
#define pb push_back
#define maxn 1000010
int n;
char x[maxn];
int Next[maxn];
void prekmp(char* x,int len){
    int pre=-1,suf=0;
    Next[0]=-1;
    while(suf<len){
        while(pre!=-1&&x[suf]!=x[pre]) pre=Next[pre];
        Next[++suf]=++pre;
    }
}
int kmp(char* x,char* y){
    int lenx=strlen(x);
    int leny=strlen(y);
    int pre=0,suf=0,ans=0;
    prekmp(x,lenx);
    while(suf<leny){
        while(pre!=-1&&y[suf]!=x[pre]) pre=Next[pre];
        pre++; suf++;
        if(pre>=lenx){
            pre=Next[pre];
            ans++;
        }
    }
    return ans;
}
int main(){
#ifdef LOCAL
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
scanf("%d",&n);
FOR(i,1,n+1){
    scanf("%s",x);
    int len=strlen(x);
    prekmp(x,len);
    printf("Case #%d: ",i);
    queue<int> xx;
    for(int j=len;j;j=Next[j]){
            xx.push(len-Next[j]);
    }
    int ans=SZ(xx);
    printf("%d\n",ans);
    FOR(j,0,ans-1){
        printf("%d ",xx.front());
        xx.pop();
    }
    printf("%d\n",xx.front());xx.pop();
}
//system("pause");
#ifdef LOCAL
fclose(stdin);
fclose(stdout);
#endif
return 0;
}
ac代码

 


 

循环节定理(保留位)

如果有len%=(len-next[len])==0,则字符串由循环节构成,最小循环节长度为len-next[len],主指针失配时每次向前固定跳len-next[len]。

需要明白的是,该定理的成立是依赖于指针快速滚动的,只有当条件成立时,才会出现字符串由循环节构成。

在一般的情况下,next数组时严格递增且满足等差数列性质,除了最后一次外每次向前滚动的长度相等,只有当每次向前滚动的长度大于目前长度时才会出现滚动长度的变化。

而且不难证明,这样的长度变化不会超过log(len)次


 

HDU 3746

求最少添加多少任意字符使得字符串由一个以上的循环节构成

先求出最小循环节,然后补全即可

//#define LOCAL
#include <cstring>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <bitset>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
#define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z))
// X_INIT=0  mem_Macro
#define INF (1<<29)
#define MOD 1000000007ll
#define FOR(i,j,k) for(int i=j;i<=k;i++)
#define FORD(i,j,k) for(int i=j;i>=k;i--)
#define LL long long
#define SZ(x) int(x.size())
#define pb push_back
#define maxn 1000010
#define maxm 1000010 
char a[maxn],b[maxm];
int Next[maxm];
int n,m,t;
inline LL read(){
    LL f=1,ans=0;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while('0'<=ch&&ch<='9'){ans=ans*10+ch-'0';ch=getchar();}
    return ans*f;
}
void doit(){
    int pre=0;
    Next[0]=0,Next[1]=0;
    FOR(suf,2,m){
        while(pre>0&&b[pre+1]!=b[suf]) pre=Next[pre];
        if(b[pre+1]==b[suf]) pre++;
        Next[suf]=pre;
    }
    return;
}
void kmp(){
    int pre=0,ans=0;
    //Next[0]=0,Next[1]=0;
    FOR(suf,1,n){
        while(pre>0&&b[pre+1]!=a[suf]) pre=Next[pre];
        if(b[pre+1]==a[suf]) pre++;
        if(pre==m) {ans++; pre=Next[pre];}
    }
    cout<<ans<<endl;
    return;
}
int main(){
#ifdef LOCAL
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
scanf("%d",&t);
FOR(i,1,t){
    scanf("%s",b+1); m=strlen(b+1);
    doit();
    int len=m-Next[m];
    if(len==m) cout<<m<<endl;//无循环节 
    else if(m%len!=0) cout<<len-m%len<<endl;//可扩展 
    else cout<<0<<endl;//有循环节 
} 
#ifdef LOCAL
fclose(stdin);
fclose(stdout);
#endif
//system(pause);
return 0;
}
ac代码

HDU 1358

给出一个字符串s,问在[0, i]区间是否有完整的循环节,若有,输出i并输出循环次数

枚举这个i,next 2~len 运用定理

//#define LOCAL
#include <cstring>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <bitset>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
#define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z))
// X_INIT=0  mem_Macro
#define INF (1<<29)
#define MOD 1000000007ll
#define FOR(i,j,k) for(int i=j;i<=k;i++)
#define FORD(i,j,k) for(int i=j;i>=k;i--)
#define LL long long
#define SZ(x) int(x.size())
#define pb push_back
#define maxn 1000010
#define maxm 1000010 
char a[maxn],b[maxm];
int Next[maxm];
int n,m,t,len;
inline LL read(){
    LL f=1,ans=0;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while('0'<=ch&&ch<='9'){ans=ans*10+ch-'0';ch=getchar();}
    return ans*f;
}
void doit(){
    int pre=0;
    Next[0]=0,Next[1]=0;
    FOR(suf,2,m){
        while(pre>0&&b[pre+1]!=b[suf]) pre=Next[pre];
        if(b[pre+1]==b[suf]) pre++;
        Next[suf]=pre;
    }
    return;
}
void kmp(){
    int pre=0,ans=0;
    FOR(suf,1,n){
        while(pre>0&&b[pre+1]!=a[suf]) pre=Next[pre];
        if(b[pre+1]==a[suf]) pre++;
        if(pre==m) {ans++; pre=Next[pre];}
    }
    cout<<ans<<endl;
    return;
}
int main(){
#ifdef LOCAL
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
t=0;
while(cin>>m&&m!=0){
    t++;
    scanf("%s",b+1); 
    doit();
    cout<<"Test case #"<<t<<endl;
    FOR(i,1,m){
        len=i-Next[i];
        if(len!=i&&i%len==0) cout<<i<<' '<<i/len<<endl;
    }
    cout<<endl;
} 
#ifdef LOCAL
fclose(stdin);
fclose(stdout);
#endif
//system(pause);
return 0;
}
ac代码

POJ 2406

求循环节最大周期周期数,除一下就好了

//#define LOCAL
#include <cstring>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <bitset>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
#define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z))
// X_INIT=0  mem_Macro
#define INF (1<<29)
#define MOD 1000000007ll
#define FOR(i,j,k) for(int i=j;i<=k;i++)
#define FORD(i,j,k) for(int i=j;i>=k;i--)
#define LL long long
#define SZ(x) int(x.size())
#define pb push_back
#define maxn 1000010
#define maxm 1000010 
char a[maxn],b[maxm];
int Next[maxm];
int n,m,t,len;
inline LL read(){
    LL f=1,ans=0;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while('0'<=ch&&ch<='9'){ans=ans*10+ch-'0';ch=getchar();}
    return ans*f;
}
void doit(){
    int pre=0;
    Next[0]=0,Next[1]=0;
    FOR(suf,2,m){
        while(pre>0&&b[pre+1]!=b[suf]) pre=Next[pre];
        if(b[pre+1]==b[suf]) pre++;
        Next[suf]=pre;
    }
    return;
}
void kmp(){
    int pre=0,ans=0;
    //Next[0]=0,Next[1]=0;
    FOR(suf,1,n){
        while(pre>0&&b[pre+1]!=a[suf]) pre=Next[pre];
        if(b[pre+1]==a[suf]) pre++;
        if(pre==m) {ans++; pre=Next[pre];}
    }
    cout<<ans<<endl;
    return;
}
int main(){
#ifdef LOCAL
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
t=0;
while(true){
    scanf("%s",b+1); if(b[1]=='.') break;
    m=strlen(b+1);
    doit();
    len=m-Next[m];
    if(m%len) cout<<1<<endl; else cout<<m/len<<endl;
} 
#ifdef LOCAL
fclose(stdin);
fclose(stdout);
#endif
//system(pause);
return 0;
}
ac代码

hdu 4847

单字符串匹配 娱乐签到题

//#define LOCAL
#include <cstring>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <bitset>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
#define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z))
// X_INIT=0  mem_Macro
#define INF 0x3f3f3f3f
#define MOD 1000000007
#define FOR(i,j,k) for(int i=j;i<k;i+=1)
#define FORD(i,j,k) for(int i=j;i>k;i-=1)
#define uLL unsigned long long
#define LL long long
#define SZ(x) int(x.size())
#define pb push_back
char xxx[]="doge";
char x[2000010];
int Next[100];
void prekmp(char* x,int len){
    int pre=-1,suf=0;
    Next[0]=-1;
    while(suf<len){
        while(pre!=-1&&x[suf]!=x[pre]) pre=Next[pre];
        Next[++suf]=++pre;
    }
}
int kmp(char* x,char* y){
    int lenx=strlen(x);
    int leny=strlen(y);
    int pre=0,suf=0,ans=0;
    prekmp(x,lenx);
    while(suf<leny){
        while(pre!=-1&&y[suf]!=x[pre]) pre=Next[pre];
        pre++; suf++;
        if(pre>=lenx){
            pre=Next[pre];
            ans++;
        }
    }
    return ans;
}
int main(){
#ifdef LOCAL
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
int ans=0;
while(gets(x)){
    int len=strlen(x);
    FOR(i,0,len){
        if('A'<=x[i]&&x[i]<='Z') x[i]+='a'-'A';
    }
    ans+=kmp(xxx,x);
}
printf("%d\n",ans);
//system("pause");
#ifdef LOCAL
fclose(stdin);
fclose(stdout);
#endif
return 0;
}
ac代码

 

 

*2.最小最大表示法

IOI 2003WC(安徽 周源)的一个拾遗,核心思想是序化对象比对

 1 int getmin(char* x,int len){
 2     int i=0,j=1,k=0;
 3     while(i<len&&j<len){
 4         if(k==len) break;
 5         int t=x[(i+k)%len]-x[(j+k)%len];
 6         if(t==0) k++;
 7         else{
 8         if(t>0) i=i+k+1;
 9         else j=j+k+1;
10         if(i==j) j++;
11         k=0;
12         }
13     }
14     return min(i,j);
15 }
模板

模板写法及变式(待更新)


 

对字符串a和b 

若a=b(在循环意义上),则他们的最小序表示一定相同 

将字符串s看作s与它的副本s’。

若s=s'(在循环意义上),则他们的最小序表示一定相同

假设当前两字符串相等且非最小序状态,给定初始指针ij

ij不变情况下后移并匹配直到失配,由于默认两字符串相等,则次小序的一方必须滚动到新的位置(从未匹配到的地方)使得自己可能取到更小的序

ij任意一方滚动到头时匹配结束->不同

ij匹配长度等于序列长->相同

显然,字符串的最小序一定能求出


 

hdu 3374

求循环节环状字符串最大最小序起点及循环节长度

kmp周期+表示法

//#define LOCAL
#include <cstring>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <bitset>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
#define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z))
// X_INIT=0  mem_Macro
#define INF 0x3f3f3f3f
#define MOD 1000000007
#define FOR(i,j,k) for(int i=j;i<k;i+=1)
#define FORD(i,j,k) for(int i=j;i>k;i-=1)
#define uLL unsigned long long
#define LL long long
#define SZ(x) int(x.size())
#define pb push_back
#define maxn 2000010
char xx[2000010];
int ans;
int getmin(char* x,int len){
    int i=0,j=1,k=0;
    while(i<len&&j<len){
        if(k==len) break;
        int t=x[(i+k)%len]-x[(j+k)%len];
        if(t==0) k++;
        else{
        if(t>0) i=i+k+1;
        else j=j+k+1;
        if(i==j) j++;
        k=0;
        }
    }
    return min(i,j);
}
int getmax(char* x,int len){
    int i=0,j=1,k=0;
    while(i<len&&j<len){
        if(k==len) break;
        int t=x[(i+k)%len]-x[(j+k)%len];
        if(t==0) k++;
        else{
        if(t<0) i=i+k+1;
        else j=j+k+1;
        if(i==j) j++;
        k=0;
        }
    }
    return min(i,j);
}
int Next[maxn];
void prekmp(char* x,int len){
    int pre=-1,suf=0;
    Next[0]=-1;
    while(suf<len){
        while(pre!=-1&&x[suf]!=x[pre]) pre=Next[pre];
        Next[++suf]=++pre;
    }
}
int kmp(char* x,char* y){
    int lenx=strlen(x);
    int leny=strlen(y);
    int pre=0,suf=0,ans=0;
    prekmp(x,lenx);
    while(suf<leny){
        while(pre!=-1&&y[suf]!=x[pre]) pre=Next[pre];
        pre++; suf++;
        if(pre>=lenx){
            pre=Next[pre];
            ans++;
        }
    }
    return ans;
}
int main(){
#ifdef LOCAL
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
while(scanf("%s",xx)!=EOF){
    int len=strlen(xx);
    prekmp(xx,len);
    //FOR(i,0,len+1) cout<<Next[i];
    if(len%(len-Next[len])!=0) ans=1; else ans=len/(len-Next[len]);
    printf("%d %d %d %d\n",getmin(xx,len)+1,ans,getmax(xx,len)+1,ans);
}
//system("pause");
#ifdef LOCAL
fclose(stdin);
fclose(stdout);
#endif
return 0;
}
ac代码

hdu 2609

求环状字符串真实个数

表示法标准化处理+set去重

//#define LOCAL
#include <cstring>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <bitset>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
#define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z))
// X_INIT=0  mem_Macro
#define INF 0x3f3f3f3f
#define MOD 1000000007
#define FOR(i,j,k) for(int i=j;i<k;i+=1)
#define FORD(i,j,k) for(int i=j;i>k;i-=1)
#define uLL unsigned long long
#define LL long long
#define SZ(x) int(x.size())
#define pb push_back
int n,cnt,lenx;set<string> aa;
char x[1010];
int getmin(char* x,int len){
    int i=0,j=1,k=0;
    while(i<len&&j<len){
        if(k==len) break;
        int t=x[(i+k)%len]-x[(j+k)%len];
        if(t==0) k++;
        else{
        if(t>0) i=i+k+1;
        else j=j+k+1;
        if(i==j) j++;
        k=0;
        }
    }
    return min(i,j);
}
void getstr(char *x,int len){
    x[len]='\0';
    aa.insert(x);
}
int main(){
#ifdef LOCAL
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
while(scanf("%d",&n)!=EOF){
    cnt=0;
    aa.clear();
    FOR(i,0,n){
        scanf("%s",x);
        lenx=strlen(x);
        memcpy(x+lenx,x,lenx);
        getstr(x+getmin(x,lenx),lenx);
    }
    printf("%d\n",SZ(aa));
}
//system("pause");
#ifdef LOCAL
fclose(stdin);
fclose(stdout);
#endif
return 0;
}
ac代码

善用memcpy!!!用法是memcpy(y,x.begin(),x.end()) (y<-x)


3.EKMP

int Next[maxn],ex[maxn];
void pre_EKMP(char* x,int lenx) 
{
    Next[0]=lenx; 
    int j=0;
    while(j+1<lenx && x[j]==x[j+1]) j++;
    Next[1]=j;  
    int k=1;
    for(int i=2;i<lenx;i++)
    {
        int p=Next[k]+k-1;
        int L=Next[i-k];
        if(i+L<p+1) Next[i]=L; 
        else
        {
            j=max(0,p-i+1); 
            while(i+j<lenx && x[i+j]==x[j])j++;
            Next[i]=j;
            k=i; 
        }
    }
}
void EKMP(char *x,char *y) 
{
    int lenx=strlen(x); 
    int leny=strlen(y); 
    pre_EKMP(x,lenx); 
    int j=0;
    while(j<leny && j<lenx && x[j]==y[j]) j++;
    ex[0]=j;
    int k=0;
    for(int i=1;i<leny;i++)
    {
        int p=ex[k]+k-1;
        int L=Next[i-k];
        if(i+L<p+1) ex[i]=L;
        else
        {
            j=max(0,p-i+1);
            while(i+j<leny && j<lenx && y[i+j]==x[j])j++;
            ex[i]=j;
            k=i;
        }
    }
}
模板

模板写法及变式(待更新)(重要!!!勿忘!!!)


 

next[i]保存的是模式串X[0-len]与X[i-len]的最大公共前缀长度,s[0-next[i]-1]为最大公共前缀

其中,next数组的0号位为值len(恒定),1号位为暴力求出,第二位起的其余位为正常位,直到第lenX-1位

ex[i]保存的是模式串X[0-len]与匹配串S[i-len]的最大公共前缀长度,s[0-ex[i]-1]为最大公共前缀

其中,ex数组的0号位为暴力求出,第一位起的其余位为正常位,直到第lenS-1位

主要的指针为现有的最大已匹配前缀的首位K和现在假设的匹配前缀的首位I

最大已匹配前缀 S[K~K+next[K]-1]

若我们保证恒有I>K

则假设的匹配前缀的一部分S[(I~I+next[K-I]-1)=(0~K-I)=(K~I)]

若这部分包含于最大已匹配前缀,则必定失配,若不失配,则最大已匹配前缀名不副实

这是K+next[K]-1>I+next[K-I]-1时的情况

否则就更新指针逐位匹配 来更新K

求解next时就是S-S‘

求解ex时就是S-X

几乎没什么区别


 

所以说kmp和exkmp有个鬼的关系啊。

kmp是一个以失配为核心的算法,exkmp是个以匹配为核心的东西。。。这玩意更接近表示法一点吧。。。。


 


hdu 3613

提供密码表和一段密文+明文的信息

明文可能不完整,密文一定完整,求最小的完整密文+明文

不管三七二十一搞个全转换成明文的串出来,以信息为匹配串,明文为模式串做exkmp

则最小长度的密文为最小满足i+ex[i]-1=len-1的i对应的S[0~i-1]

//#define LOCAL
#include <cstring>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <bitset>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
#define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z))
// X_INIT=0  mem_Macro
#define INF 0x3f3f3f3f
#define MOD 1000000007
#define FOR(i,j,k) for(int i=j;i<k;i+=1)
#define FORD(i,j,k) for(int i=j;i>k;i-=1)
#define uLL unsigned long long
#define LL long long
#define SZ(x) int(x.size())
#define pb push_back
#define maxn 110000
char x[maxn],y[maxn],z[maxn],a[256];
int Next[maxn],ex[maxn];
int t;
void pre_EKMP(char* x,int lenx) 
{
    Next[0]=lenx; 
    int j=0;
    while(j+1<lenx && x[j]==x[j+1]) j++;
    Next[1]=j;  
    int k=1;
    for(int i=2;i<lenx;i++)
    {
        int p=Next[k]+k-1;
        int L=Next[i-k];
        if(i+L<p+1) Next[i]=L; 
        else
        {
            j=max(0,p-i+1); 
            while(i+j<lenx && x[i+j]==x[j])j++;
            Next[i]=j;
            k=i; 
        }
    }
}
//
void EKMP(char *x,int lenx,char *y,int leny) 
{
    //int lenx=strlen(x); 
    //int leny=strlen(y);
    pre_EKMP(x,lenx); 
    int j=0;
    while(j<leny && j<lenx && x[j]==y[j]) j++;
    ex[0]=j;
    int k=0;
    for(int i=1;i<leny;i++)
    {
        int p=ex[k]+k-1;
        int L=Next[i-k];
        if(i+L<p+1) ex[i]=L;
        else
        {
            j=max(0,p-i+1);
            while(i+j<leny && j<lenx && y[i+j]==x[j])j++;
            ex[i]=j;
            k=i;
        }
    }
}
int main(){
#ifdef LOCAL
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
scanf("%d",&t);
while(t--){
    map<char,char> b;
    scanf("%s%s",x,y);
    FOR(i,0,strlen(x)){
    a[i+'a']=x[i];b[x[i]]=i+'a';}
    int lenl=strlen(y);
    FOR(i,0,lenl){
    z[i]=b[y[i]];}
    //cout<<endl;
    //FOR(i,0,lenl) cout<<z[i];
    //cout<<"**"<<endl;
    EKMP(z,lenl,y,lenl);
    //cout<<"**";
    //FOR(i,0,lenl)
    //cout<<ex[i];
    int ii;
    for(ii=0;ii<lenl;ii++) if(ii+ex[ii]>=lenl&&ex[ii]<=ii)    break;
        int lll=lenl-ex[ii];
        FOR(j,0,lll)
        printf("%c",y[j]);
        FOR(j,0,lll)
        printf("%c",b[y[j]]);
printf("\n");
}
//system("pause");
#ifdef LOCAL
fclose(stdin);
fclose(stdout);
#endif
return 0;
}
ac代码

hdu 4763

找出最大的公共前后缀 ,使得原串在去掉前后缀后依然能够与此公共前后缀匹配成功

用kmp的next枚举公共前后缀,用exkmp的next检验是否依然匹配成功

//#define LOCAL
#include <cstring>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <bitset>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
#define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z))
// X_INIT=0  mem_Macro
#define INF 0x3f3f3f3f
#define MOD 1000000007
#define FOR(i,j,k) for(int i=j;i<k;i+=1)
#define FORD(i,j,k) for(int i=j;i>k;i-=1)
#define uLL unsigned long long
#define LL long long
#define SZ(x) int(x.size())
#define pb push_back
#define maxn 1000010
char x[maxn];
int n;
int Next[maxn],ex[maxn];
void pre_EKMP(char* x,int lenx) 
{
    Next[0]=lenx; 
    int j=0;
    while(j+1<lenx && x[j]==x[j+1]) j++;
    Next[1]=j;  
    int k=1;
    for(int i=2;i<lenx;i++)
    {
        int p=Next[k]+k-1;
        int L=Next[i-k];
        if(i+L<p+1) Next[i]=L; 
        else
        {
            j=max(0,p-i+1); 
            while(i+j<lenx && x[i+j]==x[j])j++;
            Next[i]=j;
            k=i; 
        }
    }
}
int Next1[maxn];
void prekmp(char* x,int len){
    int pre=-1,suf=0;
    Next1[0]=-1;
    while(suf<len){
        while(pre!=-1&&x[suf]!=x[pre]) pre=Next1[pre];
        Next1[++suf]=++pre;
    }
}
int main(){
#ifdef LOCAL
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
scanf("%d",&n);
FOR(i,0,n){
    scanf("%s",x);
    int lenx=strlen(x);
    pre_EKMP(x,lenx);
    prekmp(x,lenx);
    int j,ans=0;
    bool flag=false;
    for(j=Next1[lenx];Next1[j]!=-1;j=Next1[j]){
        FOR(k,j,lenx-j)
        if(Next[k]>j-1) {ans=j;flag=true;break;}
        if(flag) break;
    }
    printf("%d\n",ans);
}

//system("pause");
#ifdef LOCAL
fclose(stdin);
fclose(stdout);
#endif
return 0;
}
ac代码

 


 

4.manache

 1 #define maxma 2100000
 2 char ma[maxma];
 3 int mp[maxma],t;
 4 void manache(char *x,int len){
 5     int l=0;
 6     len=strlen(x);
 7     ma[l++]='-';
 8     ma[l++]='+';
 9     FOR(i,0,len)
10     ma[l++]=x[i],ma[l++]='+';
11     ma[l]='*';//0,l not_fix
12     int mx=0,id=0;///mp[i] (length+1)/2
13     FOR(i,0,l){
14         mp[i]=mx>i?min(mp[2*id-i],mx-i):1;// 2id-i-id-i,mx-i-max
15         while(ma[i+mp[i]]==ma[i-mp[i]]) mp[i]++;
16         if(i+mp[i]>mx) {
17             mx=i+mp[i];
18             id=i;
19         } 
20     }
21     return;
22 }
模板

模板写法及变式(待更新)


 

使abcde等价于#$a$b$c$d$e$*[0,len*2+1]

使得所有回文串的两侧都为$,而$又始终为奇数

mp[i]为以i为中心的字符串的回文长度,对应[i-mp[i]+1,i+mp[i]-1]

由于所有回文串的两侧都为$,而$又始终为奇数,则对应原串[(i-mp[i]+1+1)/2-1,(i+mp[i]-1-1)/2-1]

即[(i-mp[i])/2,(i+mp[i])/2-2]

相似的,主要的指针为现有的最大已匹配回文串中心ID和现在假设的匹配回文串中心的首位I

恒保证ID<=I 如果[id-mp[id]+1,id+mp[id]-1]包括i的话,即i<=id+mp[id]-1,则其的最大回文长度为min(mp[2*id-i],mx-i) //2id-i-id-i=mx-i-max

否则不存在已经求得的部分,默认从1开始

之后继续更新指针逐位匹配 来更新ID


 好像exkmp啊。。。。。。


 

hdu 3613

一个宝石序列,其中的每种宝石都有其价值

将该序列分成两部分,总价值为部分的宝石价值之和当且仅当该部分为回文串

枚举第一部分中心I(1,I,2*I-1),再去检验第二部分是否满足回文性质(2*l,l+len,2*len)

manache0号位必失配,1号位为空

//#define LOCAL
#include <cstring>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <bitset>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
#define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z))
// X_INIT=0  mem_Macro
#define INF 0x3f3f3f3f
#define MOD 1000000007
#define FOR(i,j,k) for(int i=j;i<k;i+=1)
#define FORD(i,j,k) for(int i=j;i>k;i-=1)
#define uLL unsigned long long
#define LL long long
#define SZ(x) int(x.size())
#define pb push_back
#define maxma 1100000
#define maxn 500010
int val[30];
int f[maxn];
int n;
char x[maxn];
char ma[maxma];
int mp[maxma],t;
int idx(char x){
    return x-'a';
}
void manache(char *x,int len){
    int l=0;
    len=strlen(x);
    ma[l++]='-';
    ma[l++]='$';
    FOR(i,0,len)
    ma[l++]=x[i],ma[l++]='$';
    ma[l]='#';//0,l not_fix
    int mx=0,id=0;///mp[i] (length+1)/2
    FOR(i,0,l){
        mp[i]=mx>i?min(mp[2*id-i],mx-i):1;// 2id-i-id-i,mx-i-max
        while(ma[i+mp[i]]==ma[i-mp[i]]) mp[i]++;
        if(i+mp[i]>mx) {
            mx=i+mp[i];
            id=i;
        } 
    }
    return;
}
int main(){
#ifdef LOCAL
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
scanf("%d",&n);
FOR(pp,0,n){
    FOR(i,0,26)
    scanf("%d",&val[i]);
    scanf("%s",x);
    int len=strlen(x);
    f[0]=val[idx(x[0])];
    FOR(i,1,len)
    f[i]=f[i-1]+val[idx(x[i])];
    manache(x,strlen(x));
    int ans=0;
    FOR(k,0,len-1){
        int tmp=0;
        int cnt=mp[k+2]-1;
        if(cnt==k+1) tmp+=f[k];
        cnt=mp[k+len+2]-1;
        if(cnt==len-k-1)
            tmp+=f[len-1]-f[k];
        ans=max(tmp,ans);
    }
    printf("%d\n",ans);
}
//system("pause");
#ifdef LOCAL
fclose(stdin);
fclose(stdout);
#endif
return 0;
}
ac代码

 poj 3974

求最大回文串

//#define LOCAL
#include <cstring>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <bitset>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
#define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z))
// X_INIT=0  mem_macro
#define INF (1<<29)
#define MOD 1000000007ll
#define FOR(i,j,k) for(int i=j;i<=k;i++)
#define FORD(i,j,k) for(int i=j;i>=k;i--)
#define LL long long
#define SZ(x) int(x.size())
#define pb push_back
#define maxn 1000010
#define maxm 2100000
char ch[maxn],ma[maxm];
int mp[maxm],t;
void manache(char x[],int len){
    int l=0;
    //
    ma[l++]='$';
    ma[l++]='#';
    FOR(i,0,len-1)
    ma[l++]=x[i],ma[l++]='#';
    ma[l]='*';//0,l not_fix
    int mx=0,id=0;///mp[i] (length+1)/2
    FOR(i,0,l-1){
        mp[i]=mx>i?min(mp[2*id-i],mx-i):1;// 2id-i-id-i,mx-i-max
        while(ma[i+mp[i]]==ma[i-mp[i]]) mp[i]++;
        if(i+mp[i]>mx) {
            mx=i+mp[i];
            id=i;
        } 
    }
    int ans=0;
    FOR(i,0,l-1) ans=max(ans,mp[i]);
    printf("Case %d: %d\n",++t,ans-1);
    return;
}
int main(){
#ifdef LOCAL
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
t=0;
while(scanf("%s",ch)!=EOF){
    if(ch[0]=='E'&&ch[1]=='N'&&ch[2]=='D') break;
    manache(ch,strlen(ch));
}
#ifdef LOCAL
fclose(stdin);
fclose(stdout);
#endif
//system(pause);
return 0;
}
ac代码

hdu 4513

求最大浮动回文串

更新mp时加上单调减少的限制即可

//#define LOCAL
#include <cstring>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <bitset>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
#define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z))
// X_INIT=0  mem_macro
#define INF (1<<29)
#define MOD 1000000007ll
#define FOR(i,j,k) for(int i=j;i<=k;i++)
#define FORD(i,j,k) for(int i=j;i>=k;i--)
#define LL long long
#define SZ(x) int(x.size())
#define pb push_back
#define maxn 100010
#define maxm 210000
int aa[maxn],ma[maxm];
int a[maxn],mp[maxm],t;
void manache(int x[],int len){
    int l=0;
    //
    ma[l++]=-1;
    ma[l++]=-2;
    FOR(i,0,len-1)
    ma[l++]=x[i],ma[l++]=-2;
    ma[l]=-100;//0,l not_fix
    int mx=0,id=0;///mp[i] (length+1)/2
    FOR(i,0,l-1){
        mp[i]=mx>i?min(mp[2*id-i],mx-i):1;// 2id-i-id-i,mx-i-max
        while(ma[i+mp[i]]==ma[i-mp[i]]&&ma[i-mp[i]]<=ma[i-mp[i]+2]) mp[i]++;
        if(i+mp[i]>mx) {
            mx=i+mp[i];
            id=i;
        } 
    }
    //FOR(i,0,l-1) cout<<mp[i];
    //cout<<endl;
    int ans=0;
    FOR(i,0,l-1) ans=max(ans,mp[i]);
    printf("%d\n",ans-1);
    //printf("Case %d: %d\n",++t,ans-1);
    return;
}
int main(){
#ifdef LOCAL
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
t=0;
int T,n;
scanf("%d",&T); 
while(T--){
    //if(ch[0]=='E'&&ch[1]=='N'&&ch[2]=='D') break;
    scanf("%d",&n);
    FOR(i,0,n-1)
    scanf("%d",&a[i]);
    manache(a,n);
}
#ifdef LOCAL
fclose(stdin);
fclose(stdout);
#endif
//system(pause);
return 0;
}
ac代码

hdu 3294

凯撒移位+求第一个长度至少为二的最大回文

//#define LOCAL
#include <cstring>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <bitset>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
#define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z))
// X_INIT=0  mem_macro
#define INF (1<<29)
#define MOD 1000000007ll
#define FOR(i,j,k) for(int i=j;i<=k;i++)
#define FORD(i,j,k) for(int i=j;i>=k;i--)
#define LL long long
#define SZ(x) int(x.size())
#define pb push_back
#define maxn 1000010
#define maxm 2100000
char ch[maxn],ma[maxm];
int mp[maxm],t,xx;
void manache(char x[],int len){
    int l=0;
    //
    ma[l++]='$';
    ma[l++]='#';
    FOR(i,0,len-1)
    ma[l++]=x[i],ma[l++]='#';
    ma[l]='*';//0,l not_fix
    int mx=0,id=0;///mp[i] (length+1)/2
    FOR(i,0,l-1){
        mp[i]=mx>i?min(mp[2*id-i],mx-i):1;// 2id-i-id-i,mx-i-max
        while(ma[i+mp[i]]==ma[i-mp[i]]) mp[i]++;
        if(i+mp[i]>mx) {
            mx=i+mp[i];
            id=i;
        } 
    }
    int ans=0;
    FOR(i,0,l-1) if(mp[ans]<mp[i]) ans=i;
    if(mp[ans]<3) printf("No solution!\n");
    else{
        printf("%d %d\n",(ans-mp[ans])/2,(ans-mp[ans])/2+mp[ans]-2);
        FOR(i,ans-mp[ans]+1,ans+mp[ans]-1)
        if(ma[i]!='#') printf("%c",(ma[i]-'a'-xx+26)%26+'a');
        printf("\n");
    }
    //printf("Case %d: %d\n",++t,ans-1);
    return;
}
int main(){
#ifdef LOCAL
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
t=0;
char chc;
while(scanf(" %c%s",&chc,ch)!=EOF){
    xx=chc-'a';
    //if(ch[0]=='E'&&ch[1]=='N'&&ch[2]=='D') break;
    manache(ch,strlen(ch));
}
#ifdef LOCAL
fclose(stdin);
fclose(stdout);
#endif
//system(pause);
return 0;
}
ac代码

hdu 3068

求最长回文 模板题

//#define LOCAL
#include <cstring>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <bitset>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
#define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z))
// X_INIT=0  mem_Macro
#define INF 0x3f3f3f3f
#define MOD 1000000007
#define FOR(i,j,k) for(int i=j;i<k;i+=1)
#define FORD(i,j,k) for(int i=j;i>k;i-=1)
#define uLL unsigned long long
#define LL long long
#define SZ(x) int(x.size())
#define pb push_back
char xxx[]="doge";
char x[2000010];
#define maxma 2100000
char ma[maxma];
int mp[maxma],t;
int manache(char *x,int len){
    int l=0;
    len=strlen(x);
    ma[l++]='-';
    ma[l++]='+';
    FOR(i,0,len)
    ma[l++]=x[i],ma[l++]='+';
    ma[l]='*';//0,l not_fix
    int mx=0,id=0;///mp[i] (length+1)/2
    FOR(i,0,l){
        mp[i]=mx>i?min(mp[2*id-i],mx-i):1;// 2id-i-id-i,mx-i-max
        while(ma[i+mp[i]]==ma[i-mp[i]]) mp[i]++;
        if(i+mp[i]>mx) {
            mx=i+mp[i];
            id=i;
        } 
    }
    int maxx=0;
    FOR(i,0,l){
        maxx=max(maxx,mp[i]-1);
    }
    return maxx;
}
int main(){
#ifdef LOCAL
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
while(scanf("%s",x)!=EOF){
    int len=strlen(x);
    printf("%d\n",manache(x,len));

}
#ifdef LOCAL
fclose(stdin);
fclose(stdout);
#endif
return 0;
}
ac代码

5.Trie

#define maxnode 100010
#define maxsize 30
struct Trie{
    int ch[maxnode][maxsize];
    int val[maxnode];
    int sz;
    Trie(){sz=1;memset(ch[0],0,sizeof(ch[0]));memset(val,0,sizeof(val));return;}
    int idx(char c) {return c-'a';}
    void insert(char *x,int valx){
        int u=0,len=strlen(x);
        FOR(i,0,len){
            int c=idx(x[i]);
            if(!ch[u][c]){
                memset(ch[sz],0,sizeof(ch[sz]));
                val[sz]=0;
                ch[u][c]=sz++;
            }
            u=ch[u][c];
        }
        val[u]=valx;
    }
    int insert(char *x){
        int u=0,len=strlen(x);
        FOR(i,0,len){
            int c=idx(x[i]);
            if(!ch[u][c]) return 0;
            u=ch[u][c];
        }
        return val[u];
    }
}; 
模板

貌似没啥可说的。。。主要难点是在上面挂各种东西


 

poj 3376

给n个串,求串+串(n*n个)为回文串的个数

n个串插进trie,顺手插进manache跑出来的结果(除去当前位之外的字符串是否为回文串),结尾标记照样加上

将反串放到trie里查询,如果反串为长串,就加上此节点下挂的串剩余下来的串为回文串的个数(manache跑出来的)减掉在此节点结束的字符串数

如果反串为短串(包括长度相等),就在查询当前位之外为回文串的基础上计入在当前查询节点结束的字符串数

//#define LOCAL
#include <cstring>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <bitset>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
#define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z))
// X_INIT=0  mem_Macro
#define INF 0x3f3f3f3f
#define MOD 1000000007
#define FOR(i,j,k) for(int i=j;i<k;i+=1)
#define FORD(i,j,k) for(int i=j;i>k;i-=1)
#define uLL unsigned long long
#define LL long long
#define SZ(x) int(x.size())
#define pb push_back
#define maxnode 2000010
#define maxsize 26
#define maxma 4000010
#define maxn 2000010
char ma[maxma];
int mp[maxma],t,lenx,n;
int w[maxn],bg[1000010],ed[1000010];

char x[maxn];char xx[1000010];

struct Trie{
    int ch[maxnode][maxsize];
    int val[maxnode],e[maxnode];
    int sz;
    int idx(char c) {return c-'a';}
    void iinsert(char *x,int len,int *cc){
        int u=0;
        FOR(i,0,len){
            int c=idx(x[i]);
            if(!ch[u][c]){
                //kk[u][c]=x[i];
                memset(ch[sz],0,sizeof(ch[sz]));
                val[sz]=0;
                ch[u][c]=sz++;
            }
            u=ch[u][c];
            val[u]+=cc[i];
        }
        e[u]++;
        return;
    }
    LL xquery(char *x,int len){
        int l=0;        //01234567
        ma[l++]='-';
        ma[l++]='+';
        FOR(i,0,len)
        ma[l++]=x[i],ma[l++]='+',w[i]=0;
        ma[l]='*';//0,l not_fix
        int mx=0,id=0;///mp[i] (length+1)/2
        FOR(i,0,l){
        mp[i]=mx>i?min(mp[2*id-i],mx-i):1;// 2id-i-id-i,mx-i-max
        while(ma[i+mp[i]]==ma[i-mp[i]]) mp[i]++;
        if(i+mp[i]>mx) {
            mx=i+mp[i];
            id=i;
        } 
        if(i+mp[i]>=l-1)
             w[(i-mp[i])/2] = 1;

        }
        LL anss=0;
        int c=0,i=0,u=0;//cout<<endl;
        bool flag=false;
        for(i=0;i<len;i++){
             c=idx(x[i]);
            if(!ch[u][c]) {flag=true;break;}
            u=ch[u][c];
            if(e[u]&&w[i+1]) anss+=e[u];
            
        }
        if(!flag) anss+=val[u]-e[u];
        return anss;
    }
} tt;
void manache(char *x,int len){
    int l=0;
    //len=strlen(x);
    ma[l++]='-';
    ma[l++]='+';
    FOR(i,0,len)
    ma[l++]=x[i],ma[l++]='+',w[i]=0;
    ma[l]='*';//0,l not_fix
    int mx=0,id=0;///mp[i] (length+1)/2
    FOR(i,0,l){
        mp[i]=mx>i?min(mp[2*id-i],mx-i):1;// 2id-i-id-i,mx-i-max
        while(ma[i+mp[i]]==ma[i-mp[i]]) mp[i]++;
        if(i+mp[i]>mx) {
            mx=i+mp[i];
            id=i;
        } 
        if(i+mp[i]>=l-1){
             w[(i-mp[i])/2] = 1;}

    }
    tt.iinsert(x,len,w+1);
    return;
}

int main(){
int suml=0;tt.sz=1;
scanf("%d",&n);
FOR(i,0,n){
    scanf("%d",&lenx);
    scanf("%s",x+suml);
    manache(x+suml,lenx);
    bg[i]=suml;suml+=lenx;ed[i]=suml;
    
}
LL ans=0;
FOR(i,0,n){
    int ccc=ed[i]-bg[i];
    FORD(l,ccc-1,-1) xx[ccc-l-1]=x[bg[i]+l];
    ans+=tt.xquery(xx,ccc);
}
printf("%lld\n",ans);
return 0;
}
ac代码

UVA11362

给n个字符串,看是否有一个串a为串b的前缀。

模板题

//#define LOCAL
#include <cstring>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <bitset>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;

#define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z))
// X_INIT=0  mem_Macro
#define INF 0x3f3f3f3f
#define MOD 1000000007
#define FOR(i,j,k) for(int i=j;i<k;i+=1)
#define FORD(i,j,k) for(int i=j;i>k;i-=1)
#define uLL unsigned long long
#define LL long long
#define SZ(x) int(x.size())
#define pb push_back
#define maxnode 100010
#define maxsize 27
int t,n,flag;
char s[maxnode];
struct Trie{
    int ch[maxnode][maxsize];
    int val[maxnode];
    int sz;
    void init(){sz=1;memset(ch[0],0,sizeof(ch[0]));memset(val,0,sizeof(val));return;}
    int idx(char c) {return c-'0';}
    void insert(char *x,int valx){
        int u=0,len=strlen(x);
        FOR(i,0,len){
            int c=idx(x[i]);
            //cout<<sz;
            if(ch[u][c]==0){
                memset(ch[sz],0,sizeof(ch[sz]));
                if(i!=len-1)val[sz]=1;
                ch[u][c]=sz++;
            }
            u=ch[u][c];
            if(val[u]==2) flag=false; 
        }
        if(val[u]==1) flag=false;
        val[u]=2;
        return;
    }
    int query(char *x){
        int u=0,len=strlen(x);
        FOR(i,0,len){
            int c=idx(x[i]);
            if(!ch[u][c]) return 0;
            u=ch[u][c];
        }
        return val[u];
    }
};
int main(){
#ifdef LOCAL
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
scanf("%d",&t);
while(t--){
    Trie tt;
    flag=true;
    tt.init();
    flag=true;
    scanf("%d",&n);
    FOR(i,0,n){
    scanf("%s",s);
    if(flag) 
        tt.insert(s,1);

    } 
    if(flag) printf("YES\n"); else printf("NO\n");
}
//system("pause");
#ifdef LOCAL
fclose(stdin);
fclose(stdout);
#endif
return 0;
}
ac代码

 

bzoj 1212

给出 N个单词M个句子,问每个句子中包含这些单词的最长前缀是多少。

不停地把模式串放到trie中查询,得到的结果放进dp里

//#define LOCAL
#include <cstring>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <bitset>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
#define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z))
// X_INIT=0  mem_Macro
#define INF 0x3f3f3f3f
#define MOD 1000000007
#define FOR(i,j,k) for(int i=j;i<k;i+=1)
#define FORD(i,j,k) for(int i=j;i>k;i-=1)
#define uLL unsigned long long
#define LL long long
#define SZ(x) int(x.size())
#define pb push_back
#define maxnode 10010
#define maxsize 30
bool f[2000000];
int n,m;
char x[2000000];
struct Trie{
    int ch[maxnode][maxsize];
    int val[maxnode];
    int sz;
    void init(){sz=1;memset(ch[0],0,sizeof(ch[0]));memset(val,0,sizeof(val));return;}
    int idx(char c) {return c-'a';}
    void insert(char *x){
        int u=0,len=strlen(x);
        FOR(i,0,len){
            int c=idx(x[i]);
            if(!ch[u][c]){
                memset(ch[sz],0,sizeof(ch[sz]));
                //val[sz]=0;
                ch[u][c]=sz++;
            }
            u=ch[u][c];
        }
        val[u]=2;
    }
    void query(char *x,int jj,int len){
        int u=0;
        FOR(i,jj,len){
            int c=idx(x[i]); 
            if(val[u]==2) f[i]=1;
            if(!ch[u][c]) return ;
            u=ch[u][c];
            //cout<<u;
        }
        if(val[u]==2) f[len]=1;
        return;
        //return val[u];
    }
};
int main(){
#ifdef LOCAL
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
Trie tt;tt.init();
scanf("%d%d",&n,&m);
FOR(i,0,n){
scanf("%s",x);tt.insert(x);}
FOR(j,0,m){
    scanf("%s",x);
    f[0]=1;int len=strlen(x);
    FOR(i,1,len+1) f[i]=0;
    FOR(i,1,len+1)
    if(f[i-1]) tt.query(x,i-1,len);
    FORD(i,len,-1)
    if(f[i]) {printf("%d\n",i);;break;}
}
//system("pause");
#ifdef LOCAL
fclose(stdin);
fclose(stdout);
#endif
return 0;
}
ac代码

 

bzoj 1590

给出n+m个01串,问对于这m个串中的所有串,各自跟n个串中的多少串有相同前缀(前缀长度必须等于两者长度的较小者)

每个节点存下下挂节点数和在这里结束的节点数就好了

//#define LOCAL
#include <cstring>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <bitset>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
#define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z))
// X_INIT=0  mem_Macro
#define INF 0x3f3f3f3f
#define MOD 1000000007
#define FOR(i,j,k) for(int i=j;i<k;i+=1)
#define FORD(i,j,k) for(int i=j;i>k;i-=1)
#define uLL unsigned long long
#define LL long long
#define SZ(x) int(x.size())
#define pb push_back
#define maxnode 500010
#define maxsize 2
int e[maxnode];
int ch[maxnode][maxsize];
int val[maxnode];
int sz,len,c,n,m,lens;
int x[maxnode];
void init(){sz=1;memset(ch[0],0,sizeof(ch[0]));memset(val,0,sizeof(val));return;}
    
    
    //int idx(char c) {return c-'a';}
    
    int query(int *x,int len){
        int u=0,ans=0;
        //cout<<len<<endl;
        //len=strlen(x);
        FOR(i,0,len){
            int c=x[i];            
            if(!ch[u][c]) return ans;
            u=ch[u][c];ans+=e[u];
        }
        return ans+val[u];
    }
void insert(){
        scanf("%d",&len);
        int u=0;
        FOR(i,0,len){
            scanf("%d",&c);
            if(!ch[u][c]){
                memset(ch[sz],0,sizeof(ch[sz]));
                ch[u][c]=sz++;
            }
            val[u]++;
            u=ch[u][c];
        }
        e[u]++;
        return;
}
int main(){
#ifdef LOCAL
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
scanf("%d%d",&n,&m);
init();
FOR(i,0,n)  insert();

FOR(i,0,m){
    scanf("%d",&lens);
    FOR(i,0,lens) scanf("%d",&x[i]);
        //cout<<"##"<<lens<<endl;
    printf("%d\n",query(x,lens));
}
//system("pause");
#ifdef LOCAL
fclose(stdin);
fclose(stdout);
#endif
return 0;
}
ac代码

 

loj 10050

在给定的n个整数 中选出两个进行异或运算,得到的结果最大是多少?

数字统一看成从高到低30位的二进制串,插入01tri,然后贪心

//#define LOCAL
#include <cstring>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <bitset>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
#define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z))
// X_INIT=0  mem_Macro
#define INF 0x3f3f3f3f
#define MOD 1000000007
#define FOR(i,j,k) for(int i=j;i<k;i+=1)
#define FORD(i,j,k) for(int i=j;i>k;i-=1)
#define uLL unsigned long long
#define LL long long
#define SZ(x) int(x.size())
#define pb push_back
#define maxnode 5000010
#define maxsize 2
int t,ans;
int a[100010];
struct Trie10{
    int ch[maxnode][maxsize];
    int val[maxnode];
    int sz;
    void init(){
        sz=1;memset(ch[0],0,sizeof(ch[0]));memset(val,0,sizeof(val));
    }
    void insert(int x){
        int u=0;
        FORD(i,30,-1){
            int c=(x>>i)&1;
            if(!ch[u][c]){
                memset(ch[sz],0,sizeof(ch[sz]));
                ch[u][c]=sz++;
            }
            u=ch[u][c];
        }
        return;
    }
    int query(int x){
        int u=0,ans=0;
        FORD(i,30,-1){
            int c=(x>>i)&1;
            if(ch[u][!c]){
                u=ch[u][!c]; ans+=1<<i;
            }
            else u=ch[u][c];
        }
        return ans;
    }
};
int main(){
#ifdef LOCAL
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
scanf("%d",&t);
Trie10 tt;
tt.init();
ans=0;
FOR(i,0,t){
    scanf("%d",&a[i]);
    tt.insert(a[i]); 
}
FOR(i,0,t)
ans=max(tt.query(a[i]),ans);
printf("%d",ans);
//system("pause");
#ifdef LOCAL
fclose(stdin);
fclose(stdout);
#endif
return 0;
}
ac代码

 


 

hdu 3746

提供单词及其词性和句子,保证句子中的单词都是已经给定的,判断语法对不对

你是谁???为啥会出现在这个题单里???

STL+语法分层,跟字符串匹配没关系,直接cin

//#define LOCAL
#include <cstring>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <bitset>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
#define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z))
// X_INIT=0  mem_Macro
#define INF 0x3f3f3f3f
#define MOD 1000000007
#define FOR(i,j,k) for(int i=j;i<k;i+=1)
#define FORD(i,j,k) for(int i=j;i>k;i-=1)
#define uLL unsigned long long
#define LL long long
#define SZ(x) int(x.size())
#define pb push_back
int n,m,len;
string x;
map<string,int> fun; //把每种词标号 
map<string,int> num; //将题目中给出的词标号 
map<string,char> str; //记录每种主语宾语谓语介词短语的每种形式,打表 
map<string,int> ste; //每种句子形式,打表 
void init()
{
    fun["n."]=0;
    fun["pron."]=1;
    fun["adj."]=2;
    fun["adv."]=3;
    fun["prep."]=4;
    fun["art."]=5;
    fun["vt."]=6;
    fun["vi."]=7;
    fun["v."]=8;
    
    str["450"]='A'; //介词短语 
    str["4520"]='A';
    str["41"]='A';
    str["1"]='S'; //主/宾语 
    str["50"]='S';
    str["520"]='S';
    str["7"]='I'; //不及物谓语 
    str["37"]='I';
    str["6"]='T'; //及物谓语 
    str["36"]='T';
    str["8"]='V'; //通用谓语 
    str["38"]='V';
    //句子可能的总体结构 
    ste["SI"]=1;
    ste["STS"]=1;
    ste["SV"]=1;
    ste["SVS"]=1;
    ste["ASI"]=1;
    ste["ASTS"]=1;
    ste["ASV"]=1;
    ste["ASVS"]=1;
    ste["SAI"]=1;
    ste["SATS"]=1;
    ste["SAV"]=1;
    ste["SAVS"]=1;
    ste["SIA"]=1;
    ste["STAS"]=1;
    ste["SVA"]=1;
    ste["SVAS"]=1;
    ste["STSA"]=1;
    ste["SVSA"]=1;
    return;
};
int main(){
#ifdef LOCAL
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
string x,y;
init();
cin>>n>>m;
//scanf("%d%d",&n,&m);
FOR(i,1,n+1){
    //scanf("%s%s",&x,&y);
    cin>>x>>y;
    num[x]=fun[y];
}
FOR(pp,0,m){
    string m="";
    while(cin>>x){

        len=x.length();
        if(x[0]<'a') x[0]+='a'-'A';
        if(x[len-1]=='.'){x.erase(len-1,1);m+='0'+num[x];break;}
        if(x[len-1]==',') x.erase(len-1,1);
        
        m+='0'+num[x];
    }
    string idx="",id="";
    FOR(i,0,m.length()){
        id+=m[i];
        if(str[id])    idx+=str[id],id="";
    }
    if(id!="") printf("NO\n");
    else{
        if(ste[idx]) printf("YES\n");else printf("NO\n");
    }
}
//system("pause");
#ifdef LOCAL
fclose(stdin);
fclose(stdout);
#endif
return 0;
}
ac代码

 

posted @ 2020-03-24 23:27  MukoiAoi  阅读(305)  评论(0编辑  收藏  举报