题意:给你一串n个数,求出循环来看一阶差的最小字典序:数字串看成一个顺时针的环,从某一点开始顺时针循环整个环,保证字典序最小就是答案
例如给你 2 1 3 就会得到(1-2+8 注意题意负数需要加8) (3-1) (2-3+8)-> 7 2 7 答案就是2 7 7。
典型的最小表示法。线性时间内求出最小字典序。
首先复制一遍数字串在原串后面,这样从原串任意位置开始向再后n个位置就是答案。接着双指针维护,直接双指针暴力比较数字串,当出现不同数字时,就把字典序大的那个指针向后移动尽量多的位置这样可以保证无回溯比较
#include<set> #include<map> #include<queue> #include<stack> #include<cmath> #include<vector> #include<string> #include<cstdio> #include<cstring> #include<stdlib.h> #include<iostream> #include<algorithm> using namespace std; #define eps 1E-8 /*注意可能会有输出-0.000*/ #define Sgn(x) (x<-eps? -1 :x<eps? 0:1)//x为两个浮点数差的比较,注意返回整型 #define Cvs(x) (x > 0.0 ? x+eps : x-eps)//浮点数转化 #define zero(x) (((x)>0?(x):-(x))<eps)//判断是否等于0 #define mul(a,b) (a<<b) #define dir(a,b) (a>>b) typedef long long ll; typedef unsigned long long ull; const int Inf=1<<28; const double Pi=acos(-1.0); const int Mod=1e9+7; const int Max=600010; string str; int MinRpst(int len)//最小表示法 { int i=0,j=1,k; while(i<len&&j<len) { k=0; while(k<len&&str[i+k]==str[j+k])//暴力寻找 ++k; if(k==len)//结束 return min(i,j); if(str[i+k]>str[j+k])//双指针处理无回溯的最小表示法(修改就是最大表示法) { if(i+k+1>j)//保证移动最大就会无回溯 i=i+k+1; else i=j+1; } else { if(j+k+1>i) j=j+k+1; else j=i+1; } } return min(i,j); } int main() { string tem; while(cin >> str) { tem.clear(); int len=str.size(); tem=str[0]-str[len-1]<0?str[0]-str[len-1]+8+'0':str[0]-str[len-1]+'0';//最后一个字符 for(int i=0;i<len-1;++i)//一阶差 str[i]=str[i+1]-str[i]<0?str[i+1]-str[i]+8+'0':str[i+1]-str[i]+'0'; str.erase(len-1);//删除 str+=tem;//添加 str+=str;//复制一次在后面(处理环的经典方式) int sta=MinRpst(len); for(int i=sta;i<sta+len;++i) cout << str[i]; cout << endl; } return 0; }