KMP
A - Number Sequence
裸的kmp,模板题
1 #include <iostream> 2 #include <cstring> 3 #include <string> 4 #include <map> 5 #include <set> 6 #include <algorithm> 7 #include <fstream> 8 #include <cstdio> 9 #include <cmath> 10 #include <stack> 11 #include <queue> 12 using namespace std; 13 const double Pi=3.14159265358979323846; 14 typedef long long ll; 15 const int MAXN=1000000+5; 16 const int dx[5]={0,0,0,1,-1}; 17 const int dy[5]={1,-1,0,0,0}; 18 const int INF = 0x3f3f3f3f; 19 const int NINF = 0xc0c0c0c0; 20 const ll mod=1e9+7; 21 int a[MAXN]; 22 int b[10000+5]; 23 void nextvalue (int p[],int n,int next[]) 24 { 25 int k=-1;next[0]=-1; 26 int j=0;int len=n; 27 while(j<len-1) 28 { 29 if(k==-1||p[j]==p[k]) 30 { 31 k++;j++; 32 if(p[j]!=p[k]) 33 next[j]=k; 34 else next[j]=next[k]; 35 } 36 else 37 { 38 k=next[k]; 39 } 40 } 41 } 42 int kmp(int a[],int b[],int n,int m) 43 { 44 int next[10000+5]; 45 nextvalue(b,m,next); 46 int an=n; 47 int bn=m; 48 int i=0;int j=0; 49 while(i<an&&j<bn) 50 { 51 if(a[i]==b[j]||j==-1) 52 { 53 i++;j++; 54 } 55 else 56 { 57 j=next[j]; 58 } 59 } 60 if(i==an&&j!=bn) return -1; 61 return i-bn+1; 62 } 63 64 int main() 65 { 66 int t;scanf("%d",&t);int n,m; 67 while(t--) 68 { 69 scanf("%d%d",&n,&m); 70 for(int i=0;i<n;i++) scanf("%d",&a[i]); 71 for(int i=0;i<m;i++) scanf("%d",&b[i]); 72 cout <<kmp(a,b,n,m)<<endl; 73 } 74 return 0; 75 }
B - Oulipo
这个也是直接上模板就行,但是有一个要注意的点,因为是要重复的匹配,当一次匹配满足之后,那么j的位置就在模式串后一个位置了,需要把这个位置也找到nextvalue,只需要在模式串后加一个*或者什么字符就可以。
1 #include <iostream> 2 #include <cstring> 3 #include <string> 4 #include <map> 5 #include <set> 6 #include <algorithm> 7 #include <fstream> 8 #include <cstdio> 9 #include <cmath> 10 #include <stack> 11 #include <queue> 12 using namespace std; 13 const double Pi=3.14159265358979323846; 14 typedef long long ll; 15 const int MAXN=1000000+5; 16 const int dx[5]={0,0,0,1,-1}; 17 const int dy[5]={1,-1,0,0,0}; 18 const int INF = 0x3f3f3f3f; 19 const int NINF = 0xc0c0c0c0; 20 const ll mod=1e9+7; 21 22 void nextvalue (string p,int next[]) 23 { 24 int k=-1;next[0]=-1; 25 int j=0;int len=p.size(); 26 while(j<len) 27 { 28 if(k==-1||p[j]==p[k]) 29 { 30 k++;j++; 31 if(p[j]!=p[k]) 32 next[j]=k; 33 else next[j]=next[k]; 34 } 35 else 36 { 37 k=next[k]; 38 } 39 } 40 } 41 int kmp(string str1,string str2) 42 { 43 int next[10000+5]; 44 nextvalue(str1,next);int len2=str2.size();int len1=str1.size(); 45 int i=0,j=0; 46 int ans=0; 47 while(i<len2) 48 { 49 if(str1[j]==str2[i]||j==-1) 50 { 51 i++;j++; 52 } 53 else 54 { 55 j=next[j]; 56 } 57 if(j==len1) 58 { 59 ans++; 60 j=next[j]; 61 } 62 } 63 return ans; 64 } 65 66 int main() 67 { 68 int t;scanf("%d",&t); 69 while(t--) 70 { 71 string str1,str2;cin>>str1>>str2; 72 str2=str2+'*'; 73 cout <<kmp(str1,str2)<<endl; 74 } 75 return 0; 76 }
C - 剪花布条
裸。和B一样,但是因为匹配过的字母不能用了,那么当一条匹配成功后,直接让j=0。
1 #include <iostream> 2 #include <cstring> 3 #include <string> 4 #include <map> 5 #include <set> 6 #include <algorithm> 7 #include <fstream> 8 #include <cstdio> 9 #include <cmath> 10 #include <stack> 11 #include <queue> 12 using namespace std; 13 const double Pi=3.14159265358979323846; 14 typedef long long ll; 15 const int MAXN=1000000+5; 16 const int dx[5]={0,0,0,1,-1}; 17 const int dy[5]={1,-1,0,0,0}; 18 const int INF = 0x3f3f3f3f; 19 const int NINF = 0xc0c0c0c0; 20 const ll mod=1e9+7; 21 22 void nextvalue (string p,int next[]) 23 { 24 int k=-1;next[0]=-1; 25 int j=0;int len=p.size(); 26 while(j<len) 27 { 28 if(k==-1||p[j]==p[k]) 29 { 30 k++;j++; 31 if(p[j]!=p[k]) 32 next[j]=k; 33 else next[j]=next[k]; 34 } 35 else 36 { 37 k=next[k]; 38 } 39 } 40 } 41 int kmp(string str1,string str2) 42 { 43 int next[10000+5]; 44 nextvalue(str1,next);int len2=str2.size();int len1=str1.size(); 45 int i=0,j=0; 46 int ans=0; 47 while(i<len2) 48 { 49 if(str1[j]==str2[i]||j==-1) 50 { 51 i++;j++; 52 } 53 else 54 { 55 j=next[j]; 56 } 57 if(j==len1) 58 { 59 ans++; 60 j=0; 61 } 62 } 63 return ans; 64 } 65 66 int main() 67 { 68 string str1; 69 while(cin>>str1&&str1!="#") 70 { 71 string str2;cin>>str2; 72 cout <<kmp(str2,str1)<<endl; 73 } 74 return 0; 75 }
D - Cyclic Nacklace
HDU - 3746(最小循环节)
这个题不是模式匹配问题,是最小循环节问题。找到最小循环节,然后看看这个字符串对于最小循环节相差多少,然后补就行了。
最小循环节的理解
因为next[i]数组保留的是对于i不匹配然后下个要去的位置,那么对于整个模式串来说,当下标从0开始时,next[len]就是前缀与后缀的最大相等数了。之后就很好理解了
当2*k<=len时,那么显然循环节就是k+两个k中间的,也就是len-k; 当2*k>len时,不太好理解,看这个图(灵魂画手哈哈哈)
也就是len-next[len]就是循环节,以为两个头头以及头头后面都是相同的。很奇妙发现和刚才是相同的。其实就应该是相同的。
剩下的就没有要理解的了。
1 #include <iostream> 2 #include <cstring> 3 #include <string> 4 #include <map> 5 #include <set> 6 #include <algorithm> 7 #include <fstream> 8 #include <cstdio> 9 #include <cmath> 10 #include <stack> 11 #include <queue> 12 using namespace std; 13 const double Pi=3.14159265358979323846; 14 typedef long long ll; 15 const int MAXN=1000000+5; 16 const int dx[5]={0,0,0,1,-1}; 17 const int dy[5]={1,-1,0,0,0}; 18 const int INF = 0x3f3f3f3f; 19 const int NINF = 0xc0c0c0c0; 20 const ll mod=1e9+7; 21 int nt[100000+5]; 22 void nextvalue (string p) 23 { 24 int k=-1;nt[0]=-1; 25 int j=0;int len=p.size(); 26 while(j<len) 27 { 28 if(k==-1||p[j]==p[k]) 29 { 30 k++;j++; 31 if(p[j]!=p[k]) 32 nt[j]=k; 33 else nt[j]=nt[k]; 34 } 35 else 36 { 37 k=nt[k]; 38 } 39 } 40 } 41 int main() 42 { 43 int t;cin>>t;string str; 44 while(t--) 45 { 46 cin>>str; 47 nextvalue(str); 48 int len=str.size();//求出最小循环节 49 int jie=len-nt[len];//往后加和往前加的本质是一样的, 50 if(jie==len) cout <<len<<endl; 51 else if(len%jie==0) cout <<0<<endl; 52 else cout <<jie-len%jie <<endl; 53 } 54 return 0; 55 }
E - Period
这个和D一样,只不过是求每一个位置的最小循环节。有一点要注意,因为平常使用的next数组是一个优化过的数组,即如果p[k]=p[j]时,过去也没有意义,那么我们就再往前探,但是对于这个题来说,就不应该往前探了,此时的k就表示了最大相等前后缀,探了的话就把这个性质扔掉了。
1 #include <iostream> 2 #include <cstring> 3 #include <string> 4 #include <map> 5 #include <set> 6 #include <algorithm> 7 #include <fstream> 8 #include <cstdio> 9 #include <cmath> 10 #include <stack> 11 #include <queue> 12 using namespace std; 13 const double Pi=3.14159265358979323846; 14 typedef long long ll; 15 const int MAXN=1000000+5; 16 const int dx[5]={0,0,0,1,-1}; 17 const int dy[5]={1,-1,0,0,0}; 18 const int INF = 0x3f3f3f3f; 19 const int NINF = 0xc0c0c0c0; 20 const ll mod=1e9+7; 21 int nt[1000000+5]; 22 void nextvalue (string p) 23 { 24 int k=-1;nt[0]=-1; 25 int j=0;int len=p.size(); 26 while(j<len) 27 { 28 if(k==-1||p[j]==p[k]) 29 { 30 k++;j++; 31 nt[j]=k; 32 } 33 else 34 { 35 k=nt[k]; 36 } 37 } 38 } 39 int main() 40 { 41 int n;string str; 42 int cnt=1; 43 while(cin>>n&&n) 44 { 45 cin>>str; 46 str=str+'*'; 47 nextvalue(str); 48 printf("Test case #%d\n",cnt++); 49 for(int i=2;i<=n;i++) 50 { 51 int jie=i-nt[i]; 52 if(i%jie==0&&i!=jie) 53 { 54 cout <<i<<" "<<i/jie<<endl; 55 } 56 } 57 cout <<endl; 58 } 59 return 0; 60 }
F - Power Strings
同理循环节,有完整的循环节就看看是有几个,没有的话就是1
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <cstring> 3 #include <string> 4 #include <map> 5 #include <set> 6 #include <algorithm> 7 #include <fstream> 8 #include <cstdio> 9 #include <cmath> 10 #include <stack> 11 #include <queue> 12 using namespace std; 13 const double Pi=3.14159265358979323846; 14 typedef long long ll; 15 const int MAXN=1000000+5; 16 const int dx[5]={0,0,0,1,-1}; 17 const int dy[5]={1,-1,0,0,0}; 18 const int INF = 0x3f3f3f3f; 19 const int NINF = 0xc0c0c0c0; 20 const ll mod=1e9+7; 21 int nt[1000000+5]; 22 void nextvalue (string p) 23 { 24 int k=-1;nt[0]=-1; 25 int j=0;int len=p.size(); 26 while(j<len) 27 { 28 if(k==-1||p[j]==p[k]) 29 { 30 k++;j++; 31 nt[j]=k; 32 } 33 else 34 { 35 k=nt[k]; 36 } 37 } 38 } 39 int main() 40 { 41 string str; 42 while(cin>>str&&str!=".") 43 { 44 int len=str.size(); 45 str=str+'*'; 46 nextvalue(str); 47 int jie=len-nt[len]; 48 if(len%jie) 49 cout <<1<<endl; 50 else cout <<len/jie<<endl; 51 } 52 return 0; 53 }
G - Seek the Name, Seek the Fame
这个是完全的next的数组的应用,找所有前后缀相同的的长度,首先第一个一定是len,然后就是next[len],因为前缀保留了所有的信息,那么下一个就是next[next[len]],直到0,KMP的这个算法真的好神奇。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <cstring> 3 #include <string> 4 #include <map> 5 #include <set> 6 #include <algorithm> 7 #include <fstream> 8 #include <cstdio> 9 #include <cmath> 10 #include <stack> 11 #include <queue> 12 using namespace std; 13 const double Pi=3.14159265358979323846; 14 typedef long long ll; 15 const int MAXN=1000000+5; 16 const int dx[5]={0,0,0,1,-1}; 17 const int dy[5]={1,-1,0,0,0}; 18 const int INF = 0x3f3f3f3f; 19 const int NINF = 0xc0c0c0c0; 20 const ll mod=1e9+7; 21 int nt[1000000+5]; 22 void nextvalue (string p) 23 { 24 int k=-1;nt[0]=-1; 25 int j=0;int len=p.size(); 26 while(j<len) 27 { 28 if(k==-1||p[j]==p[k]) 29 { 30 k++;j++; 31 nt[j]=k; 32 } 33 else 34 { 35 k=nt[k]; 36 } 37 } 38 } 39 int main() 40 { 41 string str; 42 while(cin>>str) 43 { 44 stack <int> S; 45 int len=str.size(); 46 str=str+'*'; 47 nextvalue(str); 48 int t=nt[len]; 49 S.push(len); 50 while(t!=0) 51 { 52 S.push(t); 53 t=nt[t]; 54 } 55 while(!S.empty()) 56 { 57 cout << S.top()<<" "; 58 S.pop(); 59 } 60 cout <<endl; 61 } 62 return 0; 63 }
H - Blue Jeans
暴力KMP就可以,因为每个的长度最多是60,且只有10个,这种小数据给出肯定是暴力的。代码稍微有点复杂,需要把判断写好
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <cstring> 3 #include <string> 4 #include <map> 5 #include <set> 6 #include <algorithm> 7 #include <fstream> 8 #include <cstdio> 9 #include <cmath> 10 #include <stack> 11 #include <queue> 12 using namespace std; 13 const double Pi=3.14159265358979323846; 14 typedef long long ll; 15 const int MAXN=5000+5; 16 const int dx[5]={0,0,0,1,-1}; 17 const int dy[5]={1,-1,0,0,0}; 18 const int INF = 0x3f3f3f3f; 19 const int NINF = 0xc0c0c0c0; 20 const ll mod=1e9+7; 21 int nt[100]; 22 void nextvalue(string p) 23 { 24 int k=-1;nt[0]=-1; 25 int len=p.size(); 26 int j=0; 27 while(j<len) 28 { 29 //cout <<"in"; 30 if(k==-1||p[j]==p[k]) 31 { 32 j++;k++; 33 if(p[j]!=p[k]) 34 nt[j]=k; 35 else 36 { 37 nt[j]=nt[k]; 38 } 39 }else 40 { 41 k=nt[k]; 42 } 43 } 44 } 45 46 int kmp(string s1,string s2) 47 { 48 int len1=s1.size(),len2=s2.size(),i=0,j=0; 49 while(i<len1&&j<len2) 50 { 51 //cout <<"on"; 52 if(s1[i]==s2[j]||j==-1) 53 { 54 i++,j++; 55 } 56 else 57 { 58 j=nt[j]; 59 } 60 if(j==len2) return 1; 61 } 62 return -1; 63 64 } 65 int main() 66 { 67 int t;cin>>t; 68 while(t--) 69 { string str[11]; 70 int n;cin>>n; 71 for(int i=1;i<=n;i++) 72 cin>>str[i]; 73 string ans="a"; 74 for(int i=1;i<=60;i++) 75 { 76 77 int sign=0;//有就继续 78 for(int j=0;j+i-1<=60;j++) 79 { 80 81 string :: iterator it; 82 it=str[1].begin(); 83 string s(it+j,it+j+i); 84 memset(nt,0,sizeof(nt)); 85 nextvalue(s); 86 //cout <<s<<"i="<<i<<"j="<<j; 87 int flag=1; 88 for(int k=2;k<=n;k++) 89 { 90 if(kmp(str[k],s)==-1) 91 { 92 flag=0; 93 break; 94 } 95 } 96 //cout <<endl; 97 if(flag==1) 98 { 99 if(ans.size()<s.size()) ans=s; 100 else if(ans.size()==s.size()&&ans>s) 101 ans=s; 102 sign=1; 103 } 104 105 } 106 //没有break 107 if(sign==0) 108 { 109 break; 110 } 111 112 } 113 if(ans=="a") cout <<"no significant commonalities\n"; 114 else if(ans.size()<3) cout <<"no significant commonalities\n" ; 115 else cout <<ans<<endl; 116 } 117 118 return 0; 119 }
I - Simpsons’ Hidden Talents
把第一个和第二个串加起来,然后求最长前后缀相同
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <cstring> 3 #include <string> 4 #include <map> 5 #include <set> 6 #include <algorithm> 7 #include <fstream> 8 #include <cstdio> 9 #include <cmath> 10 #include <stack> 11 #include <queue> 12 using namespace std; 13 const double Pi=3.14159265358979323846; 14 typedef long long ll; 15 const int MAXN=5000+5; 16 const int dx[5]={0,0,0,1,-1}; 17 const int dy[5]={1,-1,0,0,0}; 18 const int INF = 0x3f3f3f3f; 19 const int NINF = 0xc0c0c0c0; 20 const ll mod=1e9+7; 21 int nt[100000+1]; 22 void nextvalue(string p) 23 { 24 int k=-1;nt[0]=-1; 25 int len=p.size(); 26 int j=0; 27 while(j<len) 28 { 29 //cout <<"in"; 30 if(k==-1||p[j]==p[k]) 31 { 32 j++;k++; 33 nt[j]=k; 34 }else 35 { 36 k=nt[k]; 37 } 38 } 39 } 40 int main() 41 { 42 string str1;string str2; 43 while(cin>>str1) 44 { 45 cin>>str2; 46 string str=str1+str2; 47 memset(nt,0,sizeof(nt)); 48 nextvalue(str); 49 int len=str.size(); 50 if(nt[len]>min(str1.size(),str2.size())) nt[len]=min(str1.size(),str2.size()); 51 for(int i=0;i<nt[str.size()];i++) 52 cout <<str[i]; 53 if(nt[str.size()]>0) cout <<" "; 54 cout <<nt[str.size()]<<endl; 55 56 } 57 return 0; 58 }
J - Count the string
next数组+dp,这个题有点难想。看了题解
定义的dp[i]为增加第i-1个字母时,以第i-1个字母为结尾时,新增加的符合要求的字符串的个数。因为对于dp[i]来说,至少会增加next[i]这个最长的情况,那么还有就是有a[i-1]参与但是没有next[i]这么长的,那么就相当于加了一个d[next[i]],所以递推式为dp[i]=dp[next[i]]+1;
关键的一点在于状态的定义。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <cstring> 3 #include <string> 4 #include <map> 5 #include <set> 6 #include <algorithm> 7 #include <fstream> 8 #include <cstdio> 9 #include <cmath> 10 #include <stack> 11 #include <queue> 12 using namespace std; 13 const double Pi=3.14159265358979323846; 14 typedef long long ll; 15 const int MAXN=5000+5; 16 const int dx[5]={0,0,0,1,-1}; 17 const int dy[5]={1,-1,0,0,0}; 18 const int INF = 0x3f3f3f3f; 19 const int NINF = 0xc0c0c0c0; 20 const ll mod=1e9+7; 21 int nt[200000+1]; 22 int dp[200000+1]; 23 void nextvalue(string p) 24 { 25 int j=0;int k=-1;nt[0]=-1; 26 int len=p.size(); 27 while(j<len) 28 { 29 if(p[k]==p[j]||k==-1) 30 { 31 j++;k++; 32 nt[j]=k; 33 } 34 else 35 { 36 k=nt[k]; 37 } 38 } 39 } 40 int main() 41 { 42 int t;cin>>t; 43 while(t--) 44 { 45 int n;cin>>n; 46 string str;cin>>str; 47 nextvalue(str); 48 ll ans=0; 49 for(int i=1;i<=n;i++) 50 { 51 dp[i]=dp[nt[i]]+1; 52 ans=(ans+dp[i])%10007; 53 } 54 cout <<ans<<endl; 55 } 56 return 0; 57 }
K - Clairewd’s message
还是next数组的应用,因为原文的长度肯定是比密码小的,所以,原文长度最长是len/2;然后把前面的对照密码表翻译过来,然后求next数组。注意奇数和偶数分开处理,还有就是next[len]肯定是<=len/2的
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <cstring> 3 #include <string> 4 #include <map> 5 #include <set> 6 #include <algorithm> 7 #include <fstream> 8 #include <cstdio> 9 #include <cmath> 10 #include <stack> 11 #include <queue> 12 using namespace std; 13 const double Pi=3.14159265358979323846; 14 typedef long long ll; 15 const int MAXN=5000+5; 16 const int dx[5]={0,0,0,1,-1}; 17 const int dy[5]={1,-1,0,0,0}; 18 const int INF = 0x3f3f3f3f; 19 const int NINF = 0xc0c0c0c0; 20 const ll mod=1e9+7; 21 int nt[100000+4]; 22 void nextvalue(string p) 23 { 24 int j=0,k=-1,len=p.size(); 25 nt[0]=-1; 26 while(j<len) 27 { 28 if(p[j]==p[k]||k==-1) 29 { 30 j++;k++; 31 nt[j]=k; 32 } 33 else 34 { 35 k=nt[k]; 36 } 37 } 38 } 39 40 int main() 41 { 42 int t;cin>>t; 43 while(t--) 44 { 45 memset(nt,0,sizeof(nt)); 46 string str;cin>>str; 47 map<char,char> M; 48 for(int i=0;i<26;i++) 49 { 50 M[str[i]]=char('a'+i); 51 } 52 string s;cin>>s; 53 string m=s; 54 int len=s.size(); 55 if(len%2) 56 for(int i=0;i<=s.size()/2;i++) 57 { 58 s[i]=M[s[i]]; 59 } 60 else 61 { 62 for(int i=0;i<s.size()/2;i++) 63 { 64 s[i]=M[s[i]]; 65 } 66 } 67 nextvalue(s); 68 if(len%2) 69 { 70 if(nt[len]<=len-len/2+1) 71 { 72 73 string ans; 74 for(int i=0;i<len-nt[s.size()];i++) 75 { 76 cout <<m[i]; 77 ans+=M[m[i]]; 78 } 79 cout <<ans<<endl; 80 } 81 else 82 { 83 nt[len]=len/2; 84 string ans; 85 for(int i=0;i<len-nt[s.size()];i++) 86 { 87 cout <<m[i]; 88 ans+=M[m[i]]; 89 } 90 cout <<ans<<endl; 91 92 } 93 }else 94 { 95 if(nt[len]>len/2) nt[len]=len/2; 96 string ans; 97 for(int i=0;i<s.size()-nt[s.size()];i++) 98 { 99 cout <<m[i]; 100 ans+=M[m[i]]; 101 } 102 cout <<ans<<endl; 103 } 104 } 105 return 0; 106 }
L - Substrings
和前面有个题一样,这个数据略大,但是好像输出更容易,暴力枚举+KMP,这个题要不是有个很zz的问题,就直接没有调试直接过了
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <cstring> 3 #include <string> 4 #include <map> 5 #include <set> 6 #include <algorithm> 7 #include <fstream> 8 #include <cstdio> 9 #include <cmath> 10 #include <stack> 11 #include <queue> 12 using namespace std; 13 const double Pi=3.14159265358979323846; 14 typedef long long ll; 15 const int MAXN=5000+5; 16 const int dx[5]={0,0,0,1,-1}; 17 const int dy[5]={1,-1,0,0,0}; 18 const int INF = 0x3f3f3f3f; 19 const int NINF = 0xc0c0c0c0; 20 const ll mod=1e9+7; 21 int nt1[100+4]; 22 int nt2[100+4]; 23 void nextvalue1(string p) 24 { 25 int j=0,k=-1,len=p.size(); 26 nt1[0]=-1; 27 while(j<len) 28 { 29 if(p[j]==p[k]||k==-1) 30 { 31 j++;k++; 32 nt1[j]=k; 33 } 34 else 35 { 36 k=nt1[k]; 37 } 38 } 39 } 40 void nextvalue2(string p) 41 { 42 int j=0,k=-1,len=p.size(); 43 nt2[0]=-1; 44 while(j<len) 45 { 46 if(p[j]==p[k]||k==-1) 47 { 48 j++;k++; 49 nt2[j]=k; 50 } 51 else 52 { 53 k=nt2[k]; 54 } 55 } 56 } 57 int kmp1(string str1,string str2) 58 { 59 int i=0,j=0,len1=str1.size(),len2=str2.size(); 60 while(i<len1&&j<len2) 61 { 62 if(str1[i]==str2[j]||j==-1) 63 { 64 i++;j++; 65 } 66 else 67 { 68 j=nt1[j]; 69 } 70 if(j==len2) return 1; 71 } 72 return 0; 73 } 74 int kmp2(string str1,string str2) 75 { 76 int i=0,j=0,len1=str1.size(),len2=str2.size(); 77 while(i<len1&&j<len2) 78 { 79 if(str1[i]==str2[j]||j==-1) 80 { 81 i++;j++; 82 } 83 else 84 { 85 j=nt2[j]; 86 } 87 if(j==len2) return 1; 88 } 89 return 0; 90 } 91 string str[101]; 92 int main() 93 { 94 int t;scanf("%d",&t); 95 while(t--) 96 { 97 int ans=0; 98 int n;scanf("%d",&n); 99 for(int i=1;i<=n;i++) 100 cin>>str[i]; 101 int len1=str[1].size(); 102 for(int i=1;i<=len1;i++) 103 { 104 int sign=0; 105 for(int j=0;j+i<=len1;j++) 106 { memset(nt1,0,sizeof(nt1)); 107 memset(nt2,0,sizeof(nt2)); 108 string :: iterator it; 109 it=str[1].begin(); 110 string s1(it+j,it+j+i); 111 string s2;s2=s1; 112 reverse(s2.begin(),s2.end()); 113 nextvalue1(s1); 114 nextvalue2(s2); 115 int flag=1; 116 for(int k=2;k<=n;k++) 117 { 118 if(!kmp1(str[k],s1)&&!kmp2(str[k],s2)) 119 { 120 flag=0; 121 break; 122 } 123 } 124 if(flag) 125 { 126 sign=1; 127 ans=max(ans,i); 128 break; 129 } 130 131 } 132 if(sign==0) 133 { 134 break; 135 } 136 } 137 cout <<ans<<endl; 138 } 139 return 0; 140 }
M- Corporate Identity
和L题一样,给了3000ms,但是500msac的。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <cstring> 3 #include <string> 4 #include <map> 5 #include <set> 6 #include <algorithm> 7 #include <fstream> 8 #include <cstdio> 9 #include <cmath> 10 #include <stack> 11 #include <queue> 12 using namespace std; 13 const double Pi=3.14159265358979323846; 14 typedef long long ll; 15 const int MAXN=5000+5; 16 const int dx[5]={0,0,0,1,-1}; 17 const int dy[5]={1,-1,0,0,0}; 18 const int INF = 0x3f3f3f3f; 19 const int NINF = 0xc0c0c0c0; 20 const ll mod=1e9+7; 21 int nt1[205]; 22 void nextvalue1(string p) 23 { 24 int j=0,k=-1,len=p.size(); 25 nt1[0]=-1; 26 while(j<len) 27 { 28 if(p[j]==p[k]||k==-1) 29 { 30 j++;k++; 31 nt1[j]=k; 32 } 33 else 34 { 35 k=nt1[k]; 36 } 37 } 38 } 39 40 int kmp1(string str1,string str2) 41 { 42 int i=0,j=0,len1=str1.size(),len2=str2.size(); 43 while(i<len1&&j<len2) 44 { 45 if(str1[i]==str2[j]||j==-1) 46 { 47 i++;j++; 48 } 49 else 50 { 51 j=nt1[j]; 52 } 53 if(j==len2) return 1; 54 } 55 return 0; 56 } 57 string str[4001]; 58 int main() 59 { 60 int n; 61 while(cin>>n&&n) 62 { 63 string ans;ans="{"; 64 for(int i=1;i<=n;i++) 65 cin>>str[i]; 66 int len1=str[1].size(); 67 for(int i=1;i<=len1;i++) 68 { 69 int sign=0; 70 for(int j=0;j+i<=len1;j++) 71 { memset(nt1,0,sizeof(nt1)); 72 string :: iterator it; 73 it=str[1].begin(); 74 string s1(it+j,it+j+i); 75 76 nextvalue1(s1); 77 int flag=1; 78 for(int k=2;k<=n;k++) 79 { 80 if(!kmp1(str[k],s1)) 81 { 82 flag=0; 83 break; 84 } 85 } 86 if(flag) 87 { 88 sign=1; 89 if(ans.size()<s1.size()||(ans.size()==s1.size()&&ans>s1)) 90 ans=s1; 91 } 92 93 } 94 if(sign==0) 95 { 96 break; 97 } 98 } 99 if(ans=="{") cout <<"IDENTITY LOST"<<endl; 100 else cout <<ans<<endl; 101 } 102 return 0; 103 }
C - String Problem
可以把字符串想成一个环,那么也就是说,从哪个位置开始可以取到最大或最小呢?
这个有一个O(n)的算法
int get_min(string s) { int n=s.size(); int i=0,j=1,k=0,t; while(i<n&&j<n&&k<n) { t=s[(i+k)%n]-s[(j+k)%n]; if(!t) k++; else { if(t>0) i=i+k+1; else j=j+k+1; if(i==j) j++; k=0; } } return i>j?j:i; }
然后,只有循环节个数是整数的才能多次重复,所以,重复次数就是循环节的个数,并且字符串包含的是整数个循环节。
又重新想了一下关于循环节。
对于当2next[len]>=len的情况,那么他们中间就会有重叠。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <cstring> 3 #include <string> 4 #include <map> 5 #include <set> 6 #include <algorithm> 7 #include <fstream> 8 #include <cstdio> 9 #include <cmath> 10 #include <stack> 11 #include <queue> 12 using namespace std; 13 const double Pi=3.14159265358979323846; 14 typedef long long ll; 15 const int MAXN=5000+5; 16 const int dx[5]={0,0,0,1,-1}; 17 const int dy[5]={1,-1,0,0,0}; 18 const int INF = 0x3f3f3f3f; 19 const int NINF = 0xc0c0c0c0; 20 const ll mod=1e9+7; 21 int nt[1000000+5]; 22 int get_min(string s) 23 { 24 int n=s.size(); 25 int i=0,j=1,k=0,t; 26 while(i<n&&j<n&&k<n) 27 { 28 t=s[(i+k)%n]-s[(j+k)%n]; 29 if(!t) k++; 30 else 31 { 32 if(t>0) i=i+k+1; 33 else j=j+k+1; 34 if(i==j) j++; 35 k=0; 36 } 37 } 38 return i>j?j:i; 39 } 40 41 int get_max(string s) 42 { 43 int n=s.size(); 44 int i=0,j=1,k=0,t; 45 while(i<n&&j<n&&k<n) 46 { 47 t=s[(i+k)%n]-s[(j+k)%n]; 48 49 if(!t) k++; 50 else 51 { 52 if(t>0) j=j+k+1; 53 else i=i+k+1; 54 if(i==j) j++; 55 k=0; 56 } 57 } 58 return i>j?j:i; 59 } 60 void nextvalue(string p) 61 { 62 int j=0,k=-1,len=p.size(); 63 nt[0]=-1; 64 while(j<len) 65 { 66 if(p[j]==p[k]||k==-1) 67 { 68 j++;k++; 69 nt[j]=k; 70 } 71 else k=nt[k]; 72 } 73 } 74 int main() 75 { 76 string str; 77 while(cin>>str) 78 { 79 memset(nt,0,sizeof(nt)); 80 nextvalue(str); 81 int num1=get_min(str); 82 int num2=get_max(str); 83 int len=str.size(); 84 int ans; 85 if(len%(len-nt[len])==0) 86 { 87 ans=len/(len-nt[len]); 88 } 89 else ans=1; 90 printf("%d %d %d %d\n",num1+1,ans,num2+1,ans); 91 } 92 return 0; 93 }