模板:
int min_max_express(char *s,int len,bool flag){//最小表示法和最大表示法写到一块儿了 int i=0,j=1,k=0; while(i<len&&j<len&&k<len){//一次就能够找着 int t=s[(j+k)%len]-s[(i+k)%len];//比较两个字符 if(t==0)k++;//相等,就后移比较下一个字符 else{ if(flag){//最小表示法 if(t>0)j+=k+1; //+(k+1)相当于直接把相等的跳过 else i+=k+1; }else{//最大表示法 if(t<0) j+=k+1; else i+=k+1; } if(i==j)j++; k=0; } } return min(i,j); }
最小表示法的意思:
对于一个字符串S,求S的循环的同构字符串S’中字典序最小的一个。由于语言能力有限,还是用实际例子来解释比较容易:
设S=bcad,且S’是S的循环同构的串。S’可以是bcad或者cadb,adbc,dbca。而且最小表示的S’是adbc。 对于字符串循环同构的最小表示法,其问题实质是求
S串的一个位置,从这个位置开始循环输出S,得到的S’字典序最小。
例题:hdu 3374
代码:
#include<stdio.h> #include<algorithm> #include<iostream> #include<string.h> using namespace std; const int max_=1e6+5; char str[max_]; int nex[max_]; void getnext(int n) { // int n=strlen(str); int i=0,k=-1; nex[i]=-1; while(i<n) { while(k>-1&&str[i]!=str[k]) k=nex[k]; nex[++i]=++k; } } int solve(bool f) { int i=0,j=1,k=0; int len=strlen(str); while(i<len&&j<len&&k<len) { int t=str[(j+k)%len]-str[(i+k)%len]; if(t==0) k++; else { if(f) {//最小表示法 if(t>0)j+=k+1; //+(k+1)相当于直接把相等的跳过 else i+=k+1; } else {//最大表示法 if(t<0) j+=k+1; else i+=k+1; } if(i==j)j++; k=0; } } return min(i,j); } int main() { while(scanf("%s",str)!=EOF) { int len=strlen(str); getnext(len); int k=len-nex[len]; int ans; int Min=solve(1); int Max=solve(0); if(len%k==0) ans=len/k; else ans=1; printf("%d %d %d %d ",Min+1,ans,Max+1,ans); } }