(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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
反转函数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; }
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; }
循环节定理(保留位)
如果有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; }
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; }
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; }
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; }
*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; }
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; }
善用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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }