hdu5442-字符串循环节&最小表示法|后缀数组(未补)|kmp+最小-Favorite Donut

http://acm.hdu.edu.cn/showproblem.php?pid=5442
给定一个字符串,长度为n。
定义有正和反两种读的方法,则其同构的串总共为2*n.
问你这么多串中 最大的同构串的起始位置。
若最大同构串出现多次。
①要求起始位置最小。(位置从1到n)
② 如果正向和反向的起始位置一样,则输出正向。

有kmp的方法,但是没怎么搞明白。
后缀数组。。我还没怎么看呢qwq
看了大佬的 用最小表示法做的。惊天为人qwq
① 正向的不用说了,直接用模板算。
关键是反向的!!,做法是求出该串的循环节,然后用长度减去循环节+min(i,j)。(i在匹配的过程中肯定是最小的那个??,如果匹配完成的话。。,因为我看别人的代码就是直接用的i。。)
! 最关键的就是用循环节反向求出 最大表示法的最大下标。

#include <bits/stdc++.h>
using namespace std;
/* 最小表示法求两次。
   一次是正序的,一次是逆序的。
*/
const int maxn=1e5;
string s;
int ans1;
int ans2;
int  MAXR(string s){
    int len=s.length();
    int i=0;int j=1;
    //int k=0;
    while(i<len/2&&j<len/2){
          int k=0;
          while(s[i+k]==s[j+k]&&k<len/2) k++;
           if(k==len/2) return min(i,j);
           if(s[i+k]<s[j+k])// 若求最大,把大于改成小于,下面也是。
              i=max(i+k+1,j+1);
          else if(s[i+k]>s[j+k])
              j=max(j+k+1,i+1);
    }
    return min(i,j);
}
int  MAXRR(string s){
    int len=s.length();
    int i=0;int j=1;
    //int k=0;
    while(i<len/2&&j<len/2){
          int k=0;
          while(s[i+k]==s[j+k]&&k<len/2) k++;
           if(k==len/2) {
              int ss=abs(i-j);//这是循环节
              return len/2-ss+min(i,j);//别人代码直接+i。、、
           }
           if(s[i+k]<s[j+k])// 若求最大,把大于改成小于,下面也是。
              i=max(i+k+1,j+1);
          else if(s[i+k]>s[j+k])
              j=max(j+k+1,i+1);
    }
     //int ss=abs(i-j);
        //cout<<ss<<"xhj"<<endl;
    return min(i,j);
}
int d;
string w1,w2;
void solve1(){
      w1=s+s;
     ans1=MAXR(w1);
}
void solve2(){
     w2=s+s;
    ans2=MAXRR(w2);
    //cout<<ans2<<"???"<<endl;
}
int main()
{   int t;
    scanf("%d",&t);
    while(t--){
         cin>>d;
         cin>>s;
         solve1();
         string s1=w1.substr(ans1,d);
         ans1++;
         reverse(s.begin(),s.end());
         solve2();
        string s2=w2.substr(ans2,d);
        //cout<<s1<<" "<<s2<<endl;
       //cout<<ans1<<" "<<ans2<<endl;
        if(s1>s2)
            printf("%d 0\n",ans1);
        else if(s2>s1)
            printf("%d 1\n",d-ans2);
        else if(s2==s1){
            if(ans1>(d-ans2))
            printf("%d 1\n",d-ans2);
            else
            printf("%d 0\n",ans1);
            }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值