bzoj2740 串 && bzoj2176 strange string(最小表示法模板)
https://konnyakuxzy.github.io/BZPRO/JudgeOnline/2740.html
题解讲的很清楚了
(好像等于的情况应该归入case2而不是case1?并不确定)
具体方法:
将串翻转,找到字典序最小且最短的后缀,然后找到以这个后缀为纯循环节的最长后缀T,则第一步是将这个后缀T提到最前面;
然后第二步是把整个串除T外部分变为其循环同构串的最小表示。
要找到字典序最小且最短的后缀,只要找到整个串的最小表示法(设最小表示法在位置i开始),然后找到S[i..n]的最短公共前后缀即可(容易发现是对的)(见代码1);也可以直接用最小表示法类似的方法一次直接求出来(见代码2)
代码1:
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<vector> 5 using namespace std; 6 #define fi first 7 #define se second 8 #define mp make_pair 9 #define pb push_back 10 typedef long long ll; 11 typedef unsigned long long ull; 12 typedef pair<int,int> pii; 13 14 int T; 15 char s[10000100]; 16 int f[10000100]; 17 int calc(const char *s,int n) 18 { 19 int i=0,j=1,k=0,t; 20 while(i<n&&j<n&&k<n) 21 { 22 t=s[(i+k)%n]-s[(j+k)%n]; 23 if(t==0) ++k; 24 else 25 { 26 if(t>0) i+=k+1; 27 else j+=k+1; 28 if(i==j) ++j; 29 k=0; 30 } 31 } 32 return min(i,j); 33 } 34 int n; 35 int an1,an2; 36 int main() 37 { 38 int i,j,t; 39 scanf("%d",&T); 40 while(T--) 41 { 42 scanf("%s",s);n=strlen(s); 43 reverse(s,s+n); 44 t=calc(s,n); 45 //printf("1t%d\n",t); 46 //t=0; 47 f[t]=0; 48 for(i=t+1,j=0;i<n;++i) 49 { 50 //j=f[i-1]; 51 while(j>0&&s[t+j]!=s[i]) j=f[t+j-1]; 52 //printf("2t%d %c %c\n",j,s[t+j],s[i]); 53 if(s[t+j]==s[i]) ++j; 54 //printf("1t%d %d %d\n",i,t+j,s[t+j]==s[i]); 55 f[i]=j; 56 } 57 //for(i=t;i<n;++i) printf("%d %d\n",i,f[i]); 58 j=f[n-1]; 59 if(j) 60 { 61 while(f[t+j-1]>0) j=f[t+j-1]; 62 t=n-j; 63 } 64 //printf("1t%d\n",t); 65 for(j=t;;) 66 { 67 //printf("3t%d %d\n",j-(n-t),t); 68 if(j>=n-t&&strncmp(s+(j-(n-t)),s+t,n-t)==0) 69 j-=n-t; 70 else 71 break; 72 } 73 t=j; 74 //printf("2t%d\n",t); 75 an1=n-t; 76 //printf("%d\n",an1); 77 //printf("%d\n",t); 78 t=calc(s,t); 79 an2=n-t; 80 printf("%d %d\n",an1,an2); 81 } 82 return 0; 83 }
代码2:(话说这个复杂度真的对吗?不确定啊?不过实测全a串还有一些随机的串的确是O(n)的,并且能A掉题)
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<vector> 5 using namespace std; 6 #define fi first 7 #define se second 8 #define mp make_pair 9 #define pb push_back 10 typedef long long ll; 11 typedef unsigned long long ull; 12 typedef pair<int,int> pii; 13 int T; 14 char s[10000100]; 15 //int f[10000100]; 16 int calc(const char *s,int n) 17 { 18 int i=0,j=1,k=0,t; 19 while(i<n&&j<n&&k<n) 20 { 21 t=s[(i+k)%n]-s[(j+k)%n]; 22 if(t==0) ++k; 23 else 24 { 25 if(t>0) i+=k+1; 26 else j+=k+1; 27 if(i==j) ++j; 28 k=0; 29 } 30 } 31 return min(i,j); 32 } 33 int n; 34 int an1,an2; 35 int main() 36 { 37 int i,j,k,t; 38 scanf("%d",&T); 39 while(T--) 40 { 41 scanf("%s",s); 42 n=strlen(s); 43 reverse(s,s+n); 44 i=0;j=1;k=0; 45 //int tt=0; 46 while(i<n&&j<n&&k<n) 47 { 48 //++tt; 49 //printf("1t%d %d %d\n",i,j,k); 50 t=((i+k<n)?s[i+k]:0)-((j+k<n)?s[j+k]:0); 51 if(t==0) ++k; 52 else 53 { 54 if(t>0) i+=(j+k<n)?k+1:k; 55 else j+=(i+k<n)?k+1:k; 56 if(i==j) ++j; 57 k=0; 58 } 59 } 60 //printf("1t%d\n",tt); 61 t=min(i,j); 62 for(j=t;;) 63 { 64 if(j>=n-t&&strncmp(s+(j-(n-t)),s+t,n-t)==0) 65 j-=n-t; 66 else 67 break; 68 } 69 t=j; 70 an1=n-t; 71 t=calc(s,t); 72 an2=n-t; 73 printf("%d %d\n",an1,an2); 74 } 75 return 0; 76 }
https://konnyakuxzy.github.io/BZPRO/JudgeOnline/2176.html
最小表示法板子
这题数据范围比较诡异,一定要用unsigned char。。。
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<vector> 5 using namespace std; 6 #define fi first 7 #define se second 8 #define mp make_pair 9 #define pb push_back 10 typedef long long ll; 11 typedef unsigned long long ull; 12 typedef pair<int,int> pii; 13 unsigned char s[10000100]; 14 int calc(const unsigned char *s,int n) 15 { 16 int i=0,j=1,k=0,t; 17 while(i<n&&j<n&&k<n) 18 { 19 t=s[(i+k)%n]-s[(j+k)%n]; 20 if(t==0) ++k; 21 else 22 { 23 if(t>0) i+=k+1; 24 else j+=k+1; 25 if(i==j) ++j; 26 k=0; 27 } 28 } 29 return min(i,j); 30 } 31 int n; 32 int main() 33 { 34 int t; 35 scanf("%d%s",&n,s); 36 t=calc(s,n); 37 printf("%s",s+t); 38 s[t]=0; 39 printf("%s",s); 40 return 0; 41 }