hdu5442

题意:
有一个len长度的环,求某一位置pos,以该点为头,其字典序最大(正逆顺序都行)。
如果有且只有一个 ,输出其 开头的下标, 下标从1 开始, 再输出0 表示顺时针  1表示逆时针
如果有多个(包括在正序与逆序),输出 开头下标最小的那个。
另外,就是顺时针 逆时针 一样且下标相等的情况  算成顺时针的。

思路:字符串的最大表示法 + kmp,kmp针对逆序的 因为跑完最大表示法返回的是最小的合法位置,在逆时针的情况下,它的最小位置即顺时针的最大位置,我们输出的位置都是对于顺时针来说的 所以还得跑一边kmp求出逆时针的最大位置即顺时针最小位置。

字符串最大表示法算法:http://blog.csdn.net/bigsungod/article/details/41514095

代码:

#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <cstdio>
#include <string>
#include <bitset>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <map>
#include <set>
#define sss(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define mem1(a) memset(a,-1,sizeof(a))
#define mem(a) memset(a,0,sizeof(a))
#define ss(a,b) scanf("%d%d",&a,&b)
#define s(a) scanf("%d",&a)
#define p(a) printf("%d\n", a)
#define INF 0x3f3f3f3f
#define w(a) while(a)
#define PI acos(-1.0)
#define LL long long
#define eps 10E-9
#define N 100010
const LL  mod = 1000000000+7;
const int SIGMA_SIZE=26;
const int MAXN=100010;
const int MAXNODE=600010;
using namespace std;
void mys(int& res) {
    int flag=0;
    char ch;
    while(!(((ch=getchar())>='0'&&ch<='9')||ch=='-'))
        if(ch==EOF)  res=INF;
    if(ch=='-')  flag=1;
    else if(ch>='0'&&ch<='9')  res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9')  res=res*10+ch-'0';
    res=flag?-res:res;
}
void myp(int a) {
    if(a>9)
        myp(a/10);
    putchar(a%10+'0');
}
/*************************THE END OF TEMPLATE************************/
char str[N];
char cs[N];
char ccs[N];
int nt[N];
int work(int len,char pat[]) {
    int i=0,j=1,k=0;
    while(i<len && j<len && k<len) {
        int t = pat[(i+k)%len] - pat[(j+k)%len];
        if(!t) k++;
        else {
            if(t>0) j = j+k+1;
            else i = i+k+1;
            if(i == j) j++;
            k = 0 ;
        }
    }
    return i<j?i:j;
}
void next() {
    int j=0,k=-1;
    nt[0]=-1;
    while(!j || ccs[j]!='\0') {
        if(k==-1 || ccs[j]==ccs[k]) {
            j++;
            k++;
            if(ccs[j]!=ccs[k])
                nt[j]=k;
            else
                nt[j]=nt[k];
        } else k=nt[k];
    }
}
int solve(int len,int pos) {
    int i=pos,j=0,num=0;
    next();
    while(i<2*len) {
        if(j==-1 || cs[i]==ccs[j]) {
            i++;
            j++;
        } else {
            j=nt[j];
        }
        if(j==len) {
            // cout<<i<<endl;
            if(i-len>len-1) break;
            num=i-len;
            j=nt[j];
        }
    }
    return num;
}
int main() {
    int t,len;
    s(t);
    w(t--) {
        s(len);
        getchar();
        gets(str);
        for(int i=0; i<len; i++) {
            cs[i]=str[len-1-i];
        }
        cs[len] = '\0';
        int posr = work(len,str);
        int posl = work(len, cs);
        int f=0,cnt=0;
        for(int i=posr, j=posl; cnt<len; i++,j++,cnt++) {
            if(i==len) i=0;
            if(j==len) j=0;
            if(str[i]>cs[j]) {
                f=1;
                break;
            }
            if(str[i]<cs[j]) {
                f=2;
                break;
            }
        }
        if( f==1) printf("%d 0\n",posr+1);
        else {
            int top=0;
            for(int i=posl; top<len ; i++) {
                if(i==len) i=0;
                ccs[top++] = cs[i];
            }
            ccs[top] = '\0';
            for(int i=len; i<2*len; i++) {
                cs[i]=cs[i-len];
            }
            cs[2*len]='\0';
            int ans = solve(len,posl);
            //     cout<<f<<endl;
            if(f==2) printf("%d 1\n",len-ans);
            else if(f==0) {
                if(len-ans >= posr+1)
                    printf("%d 0\n",posr+1);
                else
                    printf("%d 1\n",len-ans);
            }
        }
    }
    return 0;
}
/*
5
4
abab
4
aaab
8
abcdabcd
4
abcd
4
feef
*/


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值