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

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

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

 

posted @ 2018-10-24 10:03  hehe_54321  阅读(257)  评论(0编辑  收藏  举报
AmazingCounters.com