把最小表示法的坑填了
Description
给定两个项链的表示,判断他们是否可能是一条项链。
Input
输入文件只有两行,每行一个由0至9组成的字符串,描述一个项链的表示(保证项链的长度是相等的)。
Output
如果两条项链不可能同构,那么输出’No’,否则的话,第一行输出一个’Yes’
第二行输出该项链的字典序最小的表示。 设L = 项链长度,L <= 1000000。
Sample Input
2234342423
2423223434
2423223434
Sample Output
Yes
2234342423
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(' '); 40 } 41 return 0; 42 }
END