P1368 【模板】最小表示法 题解
那就是最小表示法
最小表示法就是给你的一个可以循环的字符串,找到以某一个字符为开头时字符串的字典序最小。
例如cbad的最小表示法即为adcb
一、暴力
很简单的思想,以每一个字符为开头进行扫描,得到最小表示
具体地,我们可以设置两个指针$i,j$,用$i$表示当前最小表示的开头,$j$作为循环指针
按位进行比对时,可以设置第三个指针$k$,那么每一次比对的字符就是$i+k$和$j+k$
接下来就不用多说了吧
二、优化
上述算法最慢的地方在于比对完之后k又要重置,并不能利用已经算出的大小关系,我们对下面这个字符串比对过程进行分析:
AAAAAABCD
i=1,j=2,k=5时,比对到s[6](A)<s[7](B),说明1为开头字典序更小
暴力的做法此时j应该变为3,但是我们可以注意到因为上一次已经比对到了k=5,可以说明:
s[1]=s[2] s[2]=s[3] s[3]=s[4] s[4]=s[5] s[5]=s[6] s[6]<s[7]
当$j\in[2,6]$时,必然也比以i为开头小了
所以我们可以直接让j=k+1
(妙不可言)
三、代码
#include<iostream> using namespace std; int n,a[1000001]; int main() { cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; int i=1,j=2,k=0; while(i<=n&&j<=n&&k<=n) { if(i==j) { j++; continue; } int x=i+k,y=j+k; if(x>n)x-=n; if(y>n)y-=n; int t=a[x]-a[y]; if(t==0)k++; else { if(t>0)i=i+k+1; else j=j+k+1; k=0; } } for(int l=i;l<=n;l++) cout<<a[l]<<' '; for(int l=1;l<i;l++) cout<<a[l]<<' '; }
本文来自博客园,作者:lei_yu,转载请注明原文链接:https://www.cnblogs.com/lytql/p/15000625.html