B. 비밀번호 (문자열 해시 + 2 포인트)

https://codeforces.com/problemset/problem/126/B

제목 번역

Asterix, Obelix 및 임시 파트너 인 Suffix 및 Prefix가 마침내 조화의 사원을 찾았습니다. 그러나 하모니 사원의 문은 닫 혔고 Obelix조차도 문을 열만큼 운이 좋지 않았습니다.

곧 그들은 조화의 사원 문 아래의 바위에 새겨진 S (| S | <= 1000000) 줄을 발견했습니다. 아스테릭스는 성전 문을 열기위한 암호가 틀림 없다고 추측했기 때문에 문자열을 큰 소리로 읽었지만 아무 일도 일어나지 않았습니다. 따라서 Asterix는 암호가 문자열 S의 하위 문자열 T 여야한다고 추측했습니다.

Prefix는 T가 S의 접두사라고 생각하고 Suffix는 T가 S의 접미사라고 생각하지만 Obelix는 T가 S의 일부 여야한다고 생각합니다. 즉, T는 S의 접두사도 S의 접미사도 아닙니다.

Asterix는 모든 파트너의 아이디어를 만족시키기 위해 하위 문자열 T를 선택했습니다. 동시에, 허용되는 모든 하위 문자열 변형 중에서 Asterix는 가장 긴 문자열을 선택했습니다 (Asterix는 긴 문자열을 좋아하기 때문입니다). Asterix가 하위 문자열 T를 소리내어 읽으면 사원의 문이 열립니다. (즉, S의 접두사와 S의 접미사 인 가장 긴 부분 문자열과 S의 중간에 나타난 가장 긴 부분 문자열을 찾아야합니다)

이제 문자열 S가 주어지면 위의 요구 사항을 충족하는 부분 문자열 T를 찾아야합니다.

입력 형식 :

소문자 만 포함하는 [1,1000000] 길이의 문자열 S.

출력 형식:

하위 문자열 T를 출력합니다. T가 없으면 따옴표없이 "Just a legend"를 출력합니다.


아이디어 :

접두사의 경우 왼쪽도 오른쪽도 아닌 부분 문자열이 있으면 현재 접두사보다 짧은 접두어가 해당 부분 문자열을 확실히 찾을 수 있습니다.

따라서 먼저 모든 법적 접두사 (legal : 해당 접미사가 있음)를 알아 내기 위해 전처리 한 다음 중간 세그먼트에 현재 길이를 충족하는 부분 문자열이 있는지 여부를이 분화하고 충족되면 계속 확장합니다 (l = 중간)

깨달음 : 일부 문자열 질문은 짧은 문자열을 만족시키는 긴 문자열의 본질에 대해 생각하는 데 사용할 수 있습니다.

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=1e6+100;
typedef long long LL;
const LL mod=998244353;
const LL p=131;
LL f[maxn],h[maxn];
LL a[maxn],tot=0;
LL n;
string s=" ";
LL cal(LL l,LL r){
    return (f[r]%mod-f[l-1]*h[r-l+1]%mod+mod)%mod;
}
bool check(LL len,LL val){
    for(LL i=2;i+len-1<n;i++){
        if(cal(i,i+len-1)==val) return true;
    }
    return false;
}
int main(void)
{
  cin.tie(0);std::ios::sync_with_stdio(false);
  h[0]=1;
  for(LL i=1;i<maxn;i++) h[i]=h[i-1]*p%mod;
  string c;cin>>c;
  s+=c;
  n=s.size()-1;
  for(LL i=1;i<=n;i++){
     f[i]=(f[i-1]*p%mod+s[i])%mod;
  }
  for(LL i=1;i<=n;i++){
    if(cal(1,i)==cal(n-i+1,n)){
        a[++tot]=i;
    }
  }
  LL l=0;LL r=tot;
  while(l<r){
    LL mid=(l+r+1)>>1;
    if(check(a[mid],cal(1,a[mid]))) l=mid;
    else r=mid-1;
  }
  if(l==0){
    cout<<"Just a legend"<<endl;
  }
  else{
    for(LL i=1;i<=a[l];i++){
        cout<<s[i];
    }
    cout<<endl;
  }
return 0;
}

 

추천

출처blog.csdn.net/zstuyyyyccccbbbb/article/details/113102681