[kuangbin帶你飛]專題十六 KMP & 擴展KMP & Manacher 題解報告

來刷kuangbin字符串了,字符串處理在ACM中是很重要的,通常比賽都會都1——2道有關字符串處理的題目,並且不會很難的那種,大多數時候都是用到一些KMP的性質或者找規律。ios

點擊標題可跳轉至VJ比賽題目連接。數組

A - Number Sequence

題意就是讓你去找在串A找串B首次出現的位置,如今串不是字符串,而是數字串,因此用int數組存儲便可,而後就是裸KMP。優化

代碼:spa

 1 #include <string>
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <cstring>
 5 using namespace std;
 6 
 7 int n,m;
 8 int a[1000005],b[10005];
 9 int nxt[1000005];
10 
11 void getnext(){
12     nxt[0] = -1;
13     int i = 0, j = -1;
14     while(i < n){
15         if(j == -1 || b[i] == b[j])
16             nxt[++i] = ++j;
17         else
18             j = nxt[j];
19     }
20 }
21 
22 int KMP(){
23     getnext();
24     int i = 0,j = 0;
25     while(i < n){
26         if(j == -1 || a[i] == b[j])
27             ++i,++j;
28         else
29             j = nxt[j];
30         if(j == m)
31             return i-m+1;
32     }
33     return -1;
34 }
35 
36 int main(){
37     ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0);
38     int t;
39     cin>>t;
40     while(t--){
41         cin>>n>>m;
42         for(int i = 0; i < n; i++)
43             cin>>a[i];
44         for(int i = 0; i < m; i++)
45             cin>>b[i];
46         cout << KMP() << endl;
47     }
48 
49     return 0;
50 }

 

B - Oulipo

題意就是找字符串A在字符串B中出現的次數,仍是裸KMP,當j指針等於字符串A長度時,次數加一便可。.net

代碼:3d

 1 #include <string>
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <cstring>
 5 using namespace std;
 6 
 7 string a,b;
 8 int nxt[1000005];
 9 
10 void getnext(){
11     nxt[0] = -1;
12     int i = 0, j = -1,len = b.size();
13     while(i < len){
14         if(j == -1 || b[i] == b[j])
15             nxt[++i] = ++j;
16         else
17             j = nxt[j];
18     }
19 }
20 
21 int KMP(){
22     getnext();
23     int i = 0,j = 0,sum = 0,len1 = a.size(),len2 = b.size();
24     while(i < len1){
25         if(j == -1 || a[i] == b[j])
26             ++i,++j;
27         else
28             j = nxt[j];
29         if(j == len2)
30             sum++;
31     }
32     return sum;
33 }
34 
35 int main(){
36     ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0);
37     int t;
38     cin>>t;
39     while(t--){
40         cin>>b>>a;
41         cout << KMP() << endl;
42     }
43 
44     return 0;
45 }

 

C - 剪花布條

同上一題,不過這題被匹配過的串就不能在被匹配了,因此使next數組中next[len] = 0,即當j等於len時候,從0開始從新匹配。指針

代碼:code

 1 #include <string>
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <cstring>
 5 using namespace std;
 6 
 7 string a,b;
 8 int nxt[1000005];
 9 
10 void getnext(){
11     nxt[0] = -1;
12     int i = 0, j = -1,len = b.size();
13     while(i < len){
14         if(j == -1 || b[i] == b[j])
15             nxt[++i] = ++j;
16         else
17             j = nxt[j];
18     }
19     nxt[len] = 0;
20 }
21 
22 int KMP(){
23     getnext();
24     int i = 0,j = 0,sum = 0,len1 = a.size(),len2 = b.size();
25     while(i < len1){
26         if(j == -1 || a[i] == b[j])
27             ++i,++j;
28         else
29             j = nxt[j];
30         if(j == len2)
31             sum++;
32     }
33     return sum;
34 }
35 
36 int main(){
37     ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0);
38     while(cin>>a && a[0] != '#'){
39         cin>>b;
40         cout << KMP() << endl;
41     }
42 
43     return 0;
44 }

 

D - Cyclic Nacklace

題意就是最少在當前串後面加幾個字符使得當前串變成一個循環串。blog

思路:當前串記爲S串,根據next數組的定義有S[0,next[k]-1] = S[k - next[k],k-1],既前面的部分是徹底相等的,那麼有S[0,next[len]-1] = S[len-next[len],len-1],因此S串的一個最長循環節就是len-next[len]。ip

Why?

來看下面這個手稿= =

 

 解決了這個問題以後,就好作了,若是原本就是一個循環串即len%(len-next[len])=0則輸出0,不然輸出補成循環串須要多少字符。

代碼:

 1 #include <string>
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <cstring>
 5 using namespace std;
 6 
 7 string b;
 8 int nxt[1000005];
 9 
10 void getnext(){
11     nxt[0] = -1;
12     int i = 0, j = -1,len = b.size();
13     while(i < len){
14         if(j == -1 || b[i] == b[j])
15             nxt[++i] = ++j;
16         else
17             j = nxt[j];
18     }
19 }
20 
21 int main(){
22     ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0);
23     int t;
24     cin>>t;
25     while(t--){
26         cin>>b;
27         getnext();
28         int len = b.size();
29         int cnt = len/(len - nxt[len]);
30         if(nxt[len] > 0 && len % (len-nxt[len]) == 0)
31             cout << 0 << endl;
32         else
33             cout << (cnt+1)*(len-nxt[len]) - len << endl;
34     }
35 
36     return 0;
37 }

 

E - Period

題意就是在串的前綴中找循環串,輸出位置並輸出循環節次數。

思路同上,每次判斷是否循環串便可。

代碼:

 1 #include <string>
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <cstring>
 5 using namespace std;
 6 
 7 string a;
 8 int n;
 9 int nxt[1000005];
10 
11 void getnext(){
12     nxt[0] = -1;
13     int i = 0, j = -1;
14     while(i < n){
15         if(j == -1 || a[i] == a[j])
16             nxt[++i] = ++j;
17         else
18             j = nxt[j];
19     }
20 }
21 
22 int main(){
23     ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0);
24     int tot = 1;
25     while(cin>>n && n){
26         cin>>a;
27         getnext();
28         cout << "Test case #" << tot++ << endl;
29         for(int i = 1; i <= n; i++){
30             //cerr << nxt[i] << ' ';
31             if(nxt[i] > 0 && (i)%(i-nxt[i]) == 0)
32                 cout << i << " " << i/(i-nxt[i]) << endl;
33         }
34         cout << endl;
35     }
36 
37     return 0;
38 }

 

F - The Minimum Length

原OJ出了點問題,無法作。

 

G - Power Strings

定義A*B就是把B接在串A後面,A^k = A*A^(k-1);如今給你一個串S,問把它寫成A^n形式,n最大是多少(A串要你本身找)。

很簡單的一個判斷循環串的題,若是串是循環串的話,數組循環次數,不然輸出1便可。

代碼:

 1 #include <string>
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <cstring>
 5 using namespace std;
 6 
 7 string a;
 8 int nxt[1000005];
 9 
10 void getnext(){
11     nxt[0] = -1;
12     int i = 0, j = -1,len = a.size();
13     while(i < len){
14         if(j == -1 || a[i] == a[j])
15             nxt[++i] = ++j;
16         else
17             j = nxt[j];
18     }
19 }
20 
21 int main(){
22     ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0);
23     while(cin>>a && a[0] != '.'){
24         getnext();
25         int len = a.size();
26         if(len%(len-nxt[len]) != 0)
27             cout << 1 << endl;
28         else
29             cout << len / (len - nxt[len]) << endl;
30     }
31 
32     return 0;
33 }

 

H - Seek the Name, Seek the Fame

題意:在字符串S中,找到字符串A使得A既是S的前綴串,又是S的後綴串,並輸出A串第一次出現的位置。

思路:仍是根據next數組的性質,有S[0,next[len]-1] = S[len-next[len],len-1],因此S[0,next[len]-1]是一個知足題意的串,且有S[0,next[next[len]]-1] = S[len-next[next[len]],len-1],因此S[0,next[next[len]]-1]也是一個知足題意的串,因此能夠依次往下找直到next數組值爲0位置。

代碼:

 1 #include <string>
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <cstring>
 5 #include <stack>
 6 using namespace std;
 7 
 8 string a;
 9 int nxt[1000005];
10 
11 void getnext(){
12     nxt[0] = -1;
13     int i = 0, j = -1,len = a.size();
14     while(i < len){
15         if(j == -1 || a[i] == a[j])
16             nxt[++i] = ++j;
17         else
18             j = nxt[j];
19     }
20 }
21 
22 int main(){
23     ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0);
24     while(cin>>a && a[0] != '.'){
25         getnext();
26         stack<int> q;
27         int len = a.size();
28         int cnt = 0,j = nxt[len];
29         while(j > 0){
30             q.push(j);
31             j = nxt[j];
32         }
33         while(!q.empty()){
34             cout << q.top() << " ";
35             q.pop();
36         }
37         cout << len << endl;
38     }
39 
40     return 0;
41 }

 

I - Blue Jeans

找多個串的最長公共子串,且如果字串長度小於3輸出"no significant commonalities"。

開始我還在想這不DP題嗎= =,而後發現每組最多10個串,且串長度不超過60,因此直接暴力匹配每一個字串。

代碼:

 1 #include <string>
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <cstring>
 5 #include <stack>
 6 #include <vector>
 7 using namespace std;
 8 
 9 string a,b;
10 int nxt[1000005];
11 vector<string> v;
12 int m;
13 
14 class cmp{
15 public:
16     bool operator () (const string a, const string b) const {
17         if(a.size() == b.size())
18             return a > b;
19         return a.size() < b.size();
20     }
21 };
22 
23 void getnext(string a){
24     nxt[0] = -1;
25     int i = 0, j = -1,len = a.size();
26     while(i < len){
27         if(j == -1 || a[i] == a[j])
28             nxt[++i] = ++j;
29         else
30             j = nxt[j];
31     }
32 }
33 
34 bool KMP(string b,string s){
35     int i = 0,j = 0,len1 = b.size(),len2 = s.size();
36     getnext(s);
37     while(i < len1){
38         if(j == -1 || b[i] == s[j])
39             ++i,++j;
40         else
41             j = nxt[j];
42         if(j == len2)
43             return 1;
44     }
45     return 0;
46 }
47 
48 int main(){
49     ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0);
50     int t;
51     cin>>t;
52     while(t--){
53         cin>>m>>a>>b;
54         v.clear();
55         for(int i = 0,len = a.size(); i < len; i++){
56             for(int j = 0; i+j < len; j++){
57                 string s = a.substr(i,j+1);
58                 if(KMP(b,s))
59                     v.push_back(s);
60             }
61         }
62         m -= 2;
63         while(m--){
64             cin>>b;
65             for(vector<string>::iterator it = v.begin(); it != v.end();){
66                 if(!KMP(b,*it))
67                     it = v.erase(it);
68                 else
69                     it++;
70             }
71         }
72         if(v.empty()){
73             cout << "no significant commonalities" << endl;
74             continue;
75         }
76         string ans = *max_element(v.begin(),v.end(),cmp());
77         if(ans.size() < 3)
78             cout << "no significant commonalities" << endl;
79         else
80             cout << ans << endl;
81     }
82 
83     return 0;
84 }

 

J - Simpsons’ Hidden Talents

每組輸入兩個字符串A和B,找到一個最長的字符串S使得S是A的前綴串且S是B的後綴串,輸出串S和S的長度。

思路:前面說了next數組有S[0,next[len]-1] = S[len-next[len],len-1],一樣設主串爲S,模式串爲T,一樣知足S[i-next[j],i-1] = T[0,next[j]-1]這個性質,當i=len時候,有S[len-next[j],len-1] = T[0,next[j]-1],那麼T[0,next[j]-1]便是前綴串,S[len-next[j],len-1]爲後綴串。

代碼:

 1 #include <string>
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <cstring>
 5 #include <stack>
 6 #include <vector>
 7 using namespace std;
 8 
 9 string a,b;
10 int nxt[1000005];
11 
12 void getnext(){
13     int i = 0, j = -1, len = a.size();
14     nxt[0] = -1;
15     while(i < len){
16         if(j == -1 || a[i] == a[j])
17             nxt[++i] = ++j;
18         else
19             j = nxt[j];
20     }
21 }
22 
23 int KMP(){
24     getnext();
25     int i = 0, j = 0,len1 = b.size(), len2 = a.size();;
26     while(i < len1){
27         if(j == -1 || b[i] == a[j])
28             ++i, ++j;
29         else
30             j = nxt[j];
31     }
32     if(i == len1)
33         return j;
34     return 0;
35 }
36 
37 
38 int main(){
39     ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0);
40     while(cin>>a>>b){
41         int ans = KMP();
42         if(!ans)
43             cout << 0 << endl;
44         else
45             cout << a.substr(0,ans) << ' ' << ans << endl;
46     }
47 
48     return 0;
49 }

 

K - Count the string

題意:數一個字符串每一個前綴串出現的次數並%10007。

思路:直接去找每一個前綴串出現的次數則須要len次KMP,確定會TLE,因此咱們不妨換個思惟,咱們從next數組下手,根據S[0,next[i]-1] = S[i-next[i],i-1],咱們去找第i個位置的next數組,那麼S[0,next[i]-1]這個前綴串也就在S[i-next[i],i-1]出現了一次,直到next數組值爲0爲止。

代碼:

 1 #include <string>
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <cstring>
 5 #include <stack>
 6 #include <vector>
 7 using namespace std;
 8 
 9 int n;
10 string a;
11 int nxt[1000005];
12 
13 void getnext(){
14     int i = 0, j = -1;
15     nxt[0] = -1;
16     while(i < n){
17         if(j == -1 || a[i] == a[j])
18             nxt[++i] = ++j;
19         else
20             j = nxt[j];
21     }
22 }
23 
24 int main(){
25     ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0);
26     int t;
27     cin>>t;
28     while(t--){
29         int ans = 0;
30         cin>>n>>a;
31         getnext();
32         for(int i = 1; i <= n; i++){
33             int tp = nxt[i];
34             while(tp){
35                 ans = (ans+1)%10007;
36                 tp = nxt[tp];
37             }
38         }
39         cout << (ans+n)%10007 << endl;
40     }
41 
42     return 0;
43 }

這個題是很好的一個題,不只考察了next數組的性質,還轉變了思惟方式,從去找每一個串出現次數之和變成了找每一個位置包含了哪些前綴串。

 

L - Clairewd’s message

題意:每行輸入兩個字符串,第一個字符串是一個密碼錶,a-z對應成密碼錶上的字符,第二個字符串是密文+明文,密文是完整的但明文部分不全但至少有一個字符是明文,如今問最多能夠補全多少個字符並輸出。

思路:若是沒有密文表這個東西的話就是個很簡單的字符匹配,讓密文部分儘可能長便可,但如今有了密文因此要稍作修改,咱們從(len+1)/2的位置開始KMP,由於密文完整,因此密文至少佔用了一半的字符串,固然你也能夠拆成兩個串進行匹配。

 1 #include <string>
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <cstring>
 5 #include <map>
 6 using namespace std;
 7 
 8 string a,s;
 9 int nxt[1000005];
10 
11 void getnext(){
12     int i = 0, j = -1,len = a.size();
13     nxt[0] = -1;
14     while(i < len){
15         if(j == -1 || a[i] == a[j])
16             nxt[++i] = ++j;
17         else
18             j = nxt[j];
19     }
20 }
21 
22 void KMP(){
23     getnext();
24     int i = (a.size()+1)/2,j = 0,len = a.size();
25     while(i < len){
26         if(j == -1 || s[a[i]-'a'] == a[j])
27             ++i,++j;
28         else
29             j = nxt[j];
30     }
31     cout << a;
32     map<char,char> mp;
33     for(int i = 0; i < 26; i++)
34         mp[s[i]] = char('a'+i);
35     for(int i = j; i < len-j; i++)
36         cout << mp[a[i]];
37     cout << endl;
38 }
39 
40 int main(){
41     ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0);
42     int t;
43     cin>>t;
44     while(t--){
45         cin>>s>>a;
46         KMP();
47     }
48     return 0;
49 }

 

M - Substrings

輸出最長公共子串的長度。很少說直接暴力,稍微優化一下,從長度最短的串開始枚舉子串便可。

代碼:

 1 #include <string>
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <cstring>
 5 #include <map>
 6 using namespace std;
 7 
 8 string s[105];
 9 int nxt[105];
10 int m;
11 
12 void getnext(string a){
13     int i = 0, j = -1,len = a.size();
14     nxt[0] = -1;
15     while(i < len){
16         if(j == -1 || a[i] == a[j])
17             nxt[++i] = ++j;
18         else
19             j = nxt[j];
20     }
21 }
22 
23 bool KMP(int k,string b){
24     getnext(b);
25     int i = 0,j = 0,len = s[k].size();
26     while(i < len){
27         if(j == -1 || s[k][i] == b[j])
28             ++i,++j;
29         else
30             j = nxt[j];
31         if(j == b.size())
32             return 1;
33     }
34     return 0;
35 }
36 
37 int main(){
38     ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0);
39     int t;
40     cin>>t;
41     while(t--){
42         string str = "";
43         int tot = 0;
44         cin>>m;
45         for(int i = 0; i < m; i++){
46             cin>>s[i];
47             if(str.empty() || s[i].size() < str.size())
48                 str = s[i];
49         }
50         int len = str.size();
51         for(int i = len; i > 0; i--){
52             int flag = 1;
53             for(int j = 0; i+j <= len; j++){
54                 flag = 1;
55                 string t1 = str.substr(j,i);
56                 string t2 = t1;
57                 //cout << t1 <<endl;
58                 reverse(t2.begin(),t2.end());
59                 for(int k = 0; k < m; k++){
60                     if(!KMP(k,t1) && !KMP(k,t2)){
61                         flag = 0;
62                         break;
63                     }
64                 }
65                 if(flag){
66                     tot = 1;
67                     cout << t1.size() << endl;
68                     break;
69                 }
70             }
71             if(flag)
72                 break;
73         }
74         if(!tot)
75             cout << 0 << endl;
76     }
77     return 0;
78 }

 

N - Corporate Identity

同上,不過這題輸出最長公共字串。

代碼:

 1 #include <string>
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <cstring>
 5 #include <map>
 6 using namespace std;
 7 
 8 string s[4005];
 9 int nxt[205];
10 int m;
11 
12 class cmp{
13 public:
14     bool operator () (const string a, const string b) const {
15         if(a.size() == b.size())
16             return a > b;
17         return a.size() < b.size();
18     }
19 };
20 
21 void getnext(string a){
22     int i = 0, j = -1,len = a.size();
23     nxt[0] = -1;
24     while(i < len){
25         if(j == -1 || a[i] == a[j])
26             nxt[++i] = ++j;
27         else
28             j = nxt[j];
29     }
30 }
31 
32 bool KMP(int k,string b){
33     getnext(b);
34     int i = 0,j = 0,len = s[k].size();
35     while(i < len){
36         if(j == -1 || s[k][i] == b[j])
37             ++i,++j;
38         else
39             j = nxt[j];
40         if(j == b.size())
41             return 1;
42     }
43     return 0;
44 }
45 
46 int main(){
47     ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0);
48     while(cin>>m && m){
49         vector<string> v;
50         string str;
51         int tot = 0;
52         for(int i = 0; i < m; i++){
53             cin>>s[i];
54             if(str.empty() || s[i].size() < str.size())
55                 str = s[i];
56         }
57         int len = str.size();
58         for(int i = len; i > 0; i--){
59             int flag = 1;
60             v.clear();
61             for(int j = 0; i+j <= len; j++){
62                 flag = 1;
63                 string t1 = str.substr(j,i);
64                 for(int k = 0; k < m; k++){
65                     if(!KMP(k,t1)){
66                         flag = 0;
67                         break;
68                     }
69                 }
70                 if(flag){
71                     tot = 1;
72                     v.push_back(t1);
73                 }
74             }
75             if(flag || !v.empty()){
76                 cout << *(max_element(v.begin(),v.end(),cmp())) << endl;
77                 break;
78             }
79         }
80         if(!tot)
81             cout << "IDENTITY LOST" << endl;
82     }
83     return 0;
84 }

 

O - String Problem

給你一個字符串,每次能夠位移一位即把首字母放到尾部,而後問變成字典序最小的串該如何移動且這個串出現了幾回,變成字典序最大的串該如何移動且這個串出現了幾回。

最大最小表示法模板,很少說。出現幾回判斷是否循環串便可。

代碼:

 1 #include <iostream>
 2 #include <string>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <vector>
 6 using namespace std;
 7 
 8 string s;
 9 int nxt[1000005];
10 
11 void getnext(string str){
12     int i = 0, j = -1, len = str.size();
13     nxt[0] = -1;
14     while(i < len){
15         if(j == -1 || str[i] == str[j])
16             nxt[++i] = ++j;
17         else
18             j = nxt[j];
19     }
20 }
21 int posmin(int len){
22     int i=0,j=1,k=0;
23     while(i<len&&j<len&&k<len){
24         int pan=s[(i+k)%len]-s[(j+k)%len];
25         if(!pan)
26             k++;
27         else{
28             if(pan>0)
29                 i+=k+1;
30             else
31                 j+=k+1;
32             if(i==j)
33                 j++;
34             k=0;
35         }
36     }
37     return min(i+1,j+1);
38 }
39 
40 int posmax(int len){
41     int i=0,j=1,k=0;
42     while(i<len&&j<len&&k<len){
43         int pan=s[(i+k)%len]-s[(j+k)%len];
44         if(!pan)
45             k++;
46         else{
47             if(pan>0)
48                 j+=k+1;
49             else
50                 i+=k+1;
51             if(i==j)
52                 j++;
53             k=0;
54         }
55     }
56     return min(i+1,j+1);
57 }
58 
59 int main(){
60     ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0);
61     while(cin>>s){
62         int cnt = 1;
63         int len = s.size();
64         getnext(s);
65         if(len%(len-nxt[len])==0)
66             cnt = len/(len-nxt[len]);
67         cout << posmin(len) << ' ' << cnt << ' ' << posmax(len) << ' ' << cnt << endl;
68     }
69 }

 

P - How many

問一組字符串去重後還剩多少,比較方式是隻要A能經過位移獲得B,就當作相同串,具體題目有解釋。

思路:直接去判斷A可否位移獲得B很麻煩,換個思路咱們把字符串轉化成相一樣式,而後不久能夠直接比較了嗎,利用最大最小表示法,咱們把輸入串轉化爲最大或最小表示法丟進set便可。

代碼:

 1 #include <iostream>
 2 #include <string>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <set>
 6 using namespace std;
 7 
 8 string s;
 9 int nxt[1000005];
10 
11 void getnext(string str){
12     int i = 0, j = -1, len = str.size();
13     nxt[0] = -1;
14     while(i < len){
15         if(j == -1 || str[i] == str[j])
16             nxt[++i] = ++j;
17         else
18             j = nxt[j];
19     }
20 }
21 string posmin(string s,int len){
22     int i=0,j=1,k=0;
23     while(i<len&&j<len&&k<len){
24         int pan=s[(i+k)%len]-s[(j+k)%len];
25         if(!pan)
26             k++;
27         else{
28             if(pan>0)
29                 i+=k+1;
30             else
31                 j+=k+1;
32             if(i==j)
33                 j++;
34             k=0;
35         }
36     }
37     int ans = min(i,j);
38     string res = s.substr(ans,len-ans) + s.substr(0,ans);
39     return res;
40 }
41 
42 int main(){
43     ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0);
44     int n;
45     while(cin>>n){
46         set<string> v;
47         for(int i = 0; i < n; i++){
48             cin>>s;
49             v.insert(posmin(s,s.size()));
50         }
51         cout << v.size() << endl;
52     }
53 }

 

Q - Period II

無法作。

 

R - Teacher YYF

神題= =,給你單詞的詞性,而後給你句子讓你判斷是否有語法錯誤,個人思路就是把全部合法狀況枚舉出來。但暴露了英語很差的事實,WA了,而後發現是合法狀況沒有找全,而後百度的qwq

代碼:

  1 #include <iostream>
  2 #include <string>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <map>
  6 #include <sstream>
  7 using namespace std;
  8 
  9 map<string,string> mp;
 10 map<string,bool> ste;
 11 map<string,char> str,fun;
 12 
 13 void init(){
 14     fun["n."]='0';
 15     fun["pron."]='1';
 16     fun["adj."]='2';
 17     fun["adv."]='3';
 18     fun["prep."]='4';
 19     fun["art."]='5';
 20     fun["vt."]='6';
 21     fun["vi."]='7';
 22     fun["v."]='8';
 23 
 24     str["450"]='A'; //介詞短語
 25     str["4520"]='A';
 26     str["41"]='A';
 27     str["1"]='S'; //主/賓語
 28     str["50"]='S';
 29     str["520"]='S';
 30     str["7"]='I'; //不及物謂語
 31     str["37"]='I';
 32     str["6"]='T'; //及物謂語
 33     str["36"]='T';
 34     str["8"]='V'; //通用謂語
 35     str["38"]='V';
 36     //句子可能的整體結構
 37     ste["SI"]=1;
 38     ste["STS"]=1;
 39     ste["SV"]=1;
 40     ste["SVS"]=1;
 41     ste["ASI"]=1;
 42     ste["ASTS"]=1;
 43     ste["ASV"]=1;
 44     ste["ASVS"]=1;
 45     ste["SAI"]=1;
 46     ste["SATS"]=1;
 47     ste["SAV"]=1;
 48     ste["SAVS"]=1;
 49     ste["SIA"]=1;
 50     ste["STAS"]=1;
 51     ste["SVA"]=1;
 52     ste["SVAS"]=1;
 53     ste["STSA"]=1;
 54     ste["SVSA"]=1;
 55 }
 56 
 57 bool check(string s){
 58     string res = "",c = "";
 59     for(int i = 0; i < s.size(); i++){
 60         c += s[i];
 61         if(str[c] > 0){
 62             res += str[c];
 63             c = "";
 64         }
 65     }
 66     res += c;
 67     if(ste[res])
 68         return true;
 69     return  false;
 70 }
 71 
 72 string work(string s){
 73     stringstream ss(s);
 74     string st,ans;
 75     while(ss>>st){
 76         int len = st.size(),flag = 0;
 77         st[0] = tolower(st[0]);
 78         if(st[len-1] == '.'){
 79             flag = 1;
 80             st.erase(--st.end());
 81         }
 82         if(st[len-1] == ',')
 83             st.erase(--st.end());
 84         ans += fun[mp[st]];
 85         if(flag && !check(ans))
 86             return "NO";
 87     }
 88     return "YES";
 89 }
 90 
 91 int main(){
 92     ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0);
 93     int n,m;
 94     init();
 95     while(cin>>n>>m){
 96         mp.clear();
 97         string s,s1,s2;
 98         for(int i = 0; i < n; i++){
 99             cin>>s1>>s2;
100             //cout << s1 << " " << s2 <<endl;
101             mp[s1] = s2;
102         }
103         cin.get();
104         for(int i = 0; i < m; i++){
105             getline(cin,s);
106             cout << work(s) << endl;
107         }
108     }
109 }

 

S - Best Reward

給你個價值表,a-z分別就對應相應價值,而後讓你找最長迴文串並輸出價值和。

馬拉車裸題。

代碼:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <string>
 6 #include <queue>
 7 #include <algorithm>
 8 #include <map>
 9 #include <iomanip>
10 #include <climits>
11 using namespace std;
12 
13 int n;
14 int p[1000005],sum[500005],val[27];//sum爲前i個字符價值和
15 int per[500005],pos[500005];//per標記前i個字符爲迴文串,pos標記後i個字符爲迴文串
16 
17 int manacher(string t){
18     int len = t.size(),id=0,ans=INT_MIN,temp=0;
19     for(int i = 1; i <= len; ++i)
20         sum[i] = sum[i-1] + val[t[i-1]-'a'];
21     string s = "*#";
22     for(int i = 0; i < t.size(); ++i) {
23         s += t[i];
24         s += "#";
25     }
26     for(int i = 2; i < len*2+1; ++i){
27         if(p[id] + id > i)
28             p[i]=min(p[2*id-i],p[id]+id-i);
29         else
30             p[i] = 1;
31         while(s[i-p[i]] == s[i+p[i]])
32             ++p[i];
33         if(id+p[id] < i+p[i])
34             id = i;
35         if(i-p[i] == 0)
36             per[p[i]-1] = n+1;//表示前綴(前p[i]-1個字符)是迴文串
37         if(i+p[i] == 2*len+2)
38             pos[p[i]-1] = n+1;//表示後綴(後p[i]-1個字符)是迴文串
39     }
40     for(int i = 1; i < len; ++i){
41         if(per[i] == n+1)
42             temp += sum[i];
43         if(pos[len-i] == n+1)
44             temp += sum[len]-sum[i];
45         if(temp > ans)
46             ans = temp;
47         temp=0;
48     }
49     return ans;
50 }
51 
52 int main(){
53     ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0);
54     cin>>n;
55     while(n--){
56         string s;
57         for(int i = 0; i < 26; ++i)
58             cin >> val[i];
59         cin>>s;
60         cout << manacher(s) << endl;
61     }
62     return 0;
63 }

 

T - Finding Palindromes

還沒作。

U - Palindrome

最長迴文串。懶得貼代碼了。

 

V - 吉哥系列故事――完美隊形II

還沒作。

W - Girls' research

還沒作。

X - 最長迴文

最長迴文串。

代碼:

 1 #include <cstdlib>
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <iostream>
 5 #include <algorithm>
 6 using namespace std;
 7 
 8 string t;
 9 int rad[220005];
10 
11 void manacher(int len) {
12     string s = "*#";
13     for(int i = 0; i < t.size(); ++i) {
14         s += t[i];
15         s += "#";
16     }
17     for (int i=1,j=0,k; i < len; i+=k) {
18         while (s[i-j-1] == s[i+j+1]) ++j;
19         rad[i] = j;
20         for (k = 1; k <= rad[i] && rad[i-k] != rad[i]-k; ++k) {
21             rad[i+k] = min(rad[i-k], rad[i]-k);
22         }
23         j = max(j-k, 0);
24     }
25 }
26 
27 int main(){
28     ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0);
29     while(cin>>t){
30         int len = t.size()*2+1;
31         manacher(len);
32         cout << *max_element(rad,rad+len) << endl;
33     }
34     return 0;
35 }

 

Y - Wow! Such Doge!

還沒作。

Z - Theme Section

還沒作。

 


 

還有幾道題沒作,儘快補上。主要仍是考察KMP的next數組的性質,而後還有一些先後綴的題也能夠用exKMP來作,但暫時偷個懶先水一遍吧。

相關文章
相關標籤/搜索