KMP

A - Number Sequence

 HDU - 1711 

裸的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

 HDU - 1686

这个也是直接上模板就行,但是有一个要注意的点,因为是要重复的匹配,当一次匹配满足之后,那么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 - 剪花布条

 HDU - 2087

裸。和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

 HDU - 1358

这个和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

 POJ - 2406

同理循环节,有完整的循环节就看看是有几个,没有的话就是1

 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 }
View Code

G - Seek the Name, Seek the Fame

 POJ - 2752 

这个是完全的next的数组的应用,找所有前后缀相同的的长度,首先第一个一定是len,然后就是next[len],因为前缀保留了所有的信息,那么下一个就是next[next[len]],直到0,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 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 }
View Code

H - Blue Jeans

 POJ - 3080

暴力KMP就可以,因为每个的长度最多是60,且只有10个,这种小数据给出肯定是暴力的。代码稍微有点复杂,需要把判断写好

  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 } 
View Code

I - Simpsons’ Hidden Talents

 HDU - 2594 

把第一个和第二个串加起来,然后求最长前后缀相同

 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 }
View Code

J - Count the string

 HDU - 3336

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;

关键的一点在于状态的定义。

 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 }
View Code

K - Clairewd’s message

 HDU - 4300

还是next数组的应用,因为原文的长度肯定是比密码小的,所以,原文长度最长是len/2;然后把前面的对照密码表翻译过来,然后求next数组。注意奇数和偶数分开处理,还有就是next[len]肯定是<=len/2的

  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 }
View Code

L - Substrings

 HDU - 1238

和前面有个题一样,这个数据略大,但是好像输出更容易,暴力枚举+KMP,这个题要不是有个很zz的问题,就直接没有调试直接过了

  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 }
View Code

M- Corporate Identity

 HDU - 2328 

和L题一样,给了3000ms,但是500msac的。

  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 }
View Code

C - String Problem

 HDU - 3374 

可以把字符串想成一个环,那么也就是说,从哪个位置开始可以取到最大或最小呢?

这个有一个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的情况,那么他们中间就会有重叠。

 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 }
View Code

 

posted @ 2019-05-06 10:55  Chuhanjing  阅读(493)  评论(0编辑  收藏  举报