初涉最小表示法&&bzoj1398: Vijos1382寻找主人 Necklace

把最小表示法的坑填了

Description

给定两个项链的表示,判断他们是否可能是一条项链。

Input

输入文件只有两行,每行一个由0至9组成的字符串,描述一个项链的表示(保证项链的长度是相等的)。

Output

如果两条项链不可能同构,那么输出’No’,否则的话,第一行输出一个’Yes’
第二行输出该项链的字典序最小的表示。 设L = 项链长度,L <= 1000000。

Sample Input

2234342423
2423223434

Sample Output

Yes
2234342423

题目分析

这里有最小表示法的论文https://wenku.baidu.com/view/c6c5e7335a8102d276a22fa6.html。

关键在于if (s[(i+k)%n]!=s[(j+k)%n])时的快速重配。

还有值得注意的是重配之后i有可能等于j,所以要i++,这个细节处理挺容易忘掉的。

 

是种挺优美的思想。

 1 #include<bits/stdc++.h>
 2 const int maxn = 1000035;
 3 
 4 int n,sval,tval;
 5 char s[maxn],t[maxn];
 6 
 7 int calc(char *s)
 8 {
 9     int i = 0, j = 1, k = 0;
10     while (i<n && j<n && k<n)
11     {
12         if (s[(i+k)%n]==s[(j+k)%n]) k++;
13         else{
14             if (s[(i+k)%n] > s[(j+k)%n])
15                 i += k+1;
16             else j += k+1;
17             if (i==j) i++;
18             k = 0;
19         }
20     }
21     return std::min(i, j);
22 }
23 int main()
24 {
25     scanf("%s%s",s,t);
26     n = strlen(s);
27     sval = calc(s), tval = calc(t);
28     bool fl = 1;
29     for (int i=0; i<n; i++)
30         if (s[(i+sval)%n]!=t[(i+tval)%n]){
31             fl = 0;
32             break;
33         }
34     if (!fl) puts("No");
35     else{
36         puts("Yes");
37         for (int i=sval; i<sval+n; i++)
38             putchar(s[i%n]);
39         putchar('\n');
40     }
41     return 0;
42 }

 

 

END

posted @ 2018-07-06 19:54  AntiQuality  阅读(212)  评论(0编辑  收藏  举报