ThinkingBear's Necklace


Thinking bear necklace

String hash2

this problem uses the spillover measure and bisect measure and is typetical

/*
这道题主要考点是 字符串哈希 和 二分法比较字符串
前者我不知道也没想到, 后者我虽然知道,但却因为没怎么认真用过,所以没想到
这道题感觉很有参考价值(对于以上两个知识点:
左右哈希是对字符串哈希的加强(也是对于自然溢出法的加强)
二分法比较字符串明显比直接比较好多了,以后要多多考虑二分法,分块思想,ST table , 线段树 ... (当然还有很多我还没见过的)等等这些大大减小复杂度的算法
这些算法都可以是非常灵活的,看思考的深不深了
*/
#include 
#include 
#include 
#define LOCAL
using namespace std;

typedef unsigned long long ull;
 
const int maxn = 100005;
const int seed=1e9+7;
 
int n,m;
char str[2*maxn];
ull has[2*maxn],rhas[2*maxn],pw[2*maxn];

void init()
{
    // store the p^(r-l+1) 
    pw[0]=1;
    for(int i=1;i<=2*maxn;++i)
    {
        pw[i]=pw[i-1]*seed;
    }
}
 
void init_has()
{
    //the left and right hash table are more powerful 
    for(int i=1;i<2*n;++i)
    {
        has[i]=has[i-1]*seed+(str[i]-'a'+1);
    }
    rhas[2*n+1]=0;
    for(int i=2*n;i>0;--i)
    {
        rhas[i]=rhas[i+1]*seed+(str[i]-'a'+1);
    }
}

bool check_has(int a,int b,int c)
{
    //自然溢出版哈希公式(相比于正式的字符串哈希公式:hash=((hash[r]-hash[l-1]*p^(r-l+1))%MOD+MOD)%MOD  ,  MOD is omitted): hash=hash[r]-hash[l-1]*p^(r-l+1)
    ull sum,rsum;
    rsum=rhas[b]-rhas[b+c]*pw[c];   // c(the exploratory len): b ~ b+c-1   ;  pw[c] -> p^(r-l+1)=p^c
    sum=has[a]-has[a-c]*pw[c];
    return rsum==sum;
}
 
int check(int a,int b,int c)
{
    int ret=0;
    for(int i=0;i<3;++i)    //three times of bisect
    {
        int l,r,mid,cnt=0;
        l=1,r=c;
        /*
        I just can say : Although I know the bisect, I didn't know how to and when to use it 
        the bisect is O(logn) and the compare one by one is O(n)
        so the core for me is this bisect measure .....
        */
        while(l<=r)
        {
            mid=(l+r)>>1;
            if(check_has(a,b,mid))
            {
                l=mid+1;
                cnt=mid;
            }
            else
            {
                r=mid-1;
            }
        }
        ret+=cnt;
        if(cnt==c)break;    //if the now radius reaches the max value, break
        c-=cnt+1;           //Next, the c should be lessen (cnt + 1 [the magic])
        a-=cnt+1;           // a-> the new start point (the next of magic pos)
        b+=cnt+1;
        if(c<0)break;       //c==0 couldn't break: ret++ should be carried out if i<2 ;
        if(i<2)ret++;       // plus the time of carrying out magic 
    }
    return ret;
}

int main()
{
    #ifdef LOCAL
    freopen("input.txt","r",stdin);
    #endif
    int T;
    cin>>T;
    init();
    while(T--)
    {
        cin>>str+1; // save the input from str+1
        n=strlen(str+1);
        for(int i=n+1;i<=2*n;++i)
        {
            str[i]=str[i-n];
        }
        init_has();
        int ans=1;
        for(int i=n/2;i+n/2<=2*n;++i)
        {
            int x=min(i-1,2*n-i);//  i-1 -> the left of i  ;  2*n-i -> the right of i
            x=min(x,(n-1)/2);//whether n is even or odd, the max raidus is (n-1)/2  ;  so the x shouldn't exceed the max radius
            // Actually, after i is ( (n-1)/2+1<=i<=2*n-(n-1)/2 ), the above two sentences are useless ...
            x=check(i-1,i+1,x);
            ans=max(ans,x*2+1);
        }
        cout<