Problem:
F: みこみー文字列 - Miko Mi String -

物語

みっこみっこみ〜！みんなのアイドル，田澤みこみこ！今日は〜，みこと一緒に〜，文字列アルゴリズムの練習，しよ☆

みこのとっておきのキャラ作り合言葉，「みっこみっこみ〜」は，ローマ字にすると “MikoMikoMi” になるみこ！つまり，A=“Mi”, B=“Ko” とすると，ABABAの形で書けるってことなの！こんな風に，適切にAとBを決めるとABABAの形に分解できる文字列のことを「みこみー文字列」って言うわ！文字列の名前にまでなっちゃうなんて，みこはみんなの人気者みこね！

みんなでみこみー文字列をも〜っと使っていくために，与えられた文字列がみこみー文字列かどうか判定するプログラムを作ることにしたんだけど，みこ，FizzBuzzより長いプログラムなんて書けな〜い！だから〜，みこのために〜，みこみー文字列を判定するプログラムを書いて欲しいな☆

……アンタ，いま寒いって言った！？

問題

アルファベット大文字・小文字からなる文字列Sが与えられる．
ここで，S = ABABAと書けるような，空でない2つの文字列A, Bが存在するならば，Sは「みこみー文字列」であるという．
このとき，アルファベットの大文字と小文字は違う文字として区別するものとする．
与えられた文字列がみこみー文字列であるかどうかを判定するプログラムを作成せよ．

入力形式

入力は文字列Sを含む1行のみからなる．
Sは以下の条件を満たすと仮定してよい．

1 ≤ |S| ≤ 10^6．ただし，|S|は文字列Sの長さを表す．

Sは大文字，もしくは小文字のアルファベットのみからなる．

なお，入力が非常に大きくなる場合があるため，入力の受け取りには高速な関数を用いることを推奨する．

出力形式

Sがみこみー文字列であるならば，S = ABABAを満たすようなA, Bについて，“Love AB!”と出力せよ．ただし，複数のA, Bの組が条件を満たす場合，|AB|が最小のものを出力せよ．
Sがみこみー文字列でないならば，“mitomerarenaiWA”と出力せよ．

入力例1

NicoNicoNi

出力例1

Love Nico!

入力例2

KashikoiKawaiiElichika

出力例2

mitomerarenaiWA

入力例3

LiveLiveL

出力例3

Love Live!

入力例4

AizunyanPeroPero

出力例4

mitomerarenaiWA

入力例5

AAAAAAAAAAAAAA

出力例5

Love AAAAA!

Solution in C++11 (judge verdict: Wrong Answer)

#include <cstdio>
#include <iostream>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <bitset>
#include <numeric>
#include <limits>
#include <climits>
#include <cfloat>
#include <functional>
using namespace std;

class RollingHash
{
private:
    static const int X[], Y[], M[];
    deque<char> dq;
    long long xp[3];
    long long hash[3];
public:
    RollingHash(){
        for(int i=0; i<3; ++i){
            xp[i] = 1;
            hash[i] = 0;
        }
    }
    void push_back(char c){
        dq.push_back(c);
        for(int i=0; i<3; ++i){
            hash[i] *= X[i];
            hash[i] += c;
            hash[i] %= M[i];
            xp[i] *= X[i];
            xp[i] %= M[i];
        }
    }
    void pop_back(){
        for(int i=0; i<3; ++i){
            hash[i] += M[i] - dq.back();
            hash[i] *= Y[i];
            hash[i] %= M[i];
            xp[i] *= Y[i];
            xp[i] %= M[i];
        }
        dq.pop_back();
    }
    void push_front(char c){
        dq.push_front(c);
        for(int i=0; i<3; ++i){
            hash[i] += c * xp[i];
            hash[i] %= M[i];
            xp[i] *= X[i];
            xp[i] %= M[i];
        }
    }
    void pop_front(){
        for(int i=0; i<3; ++i){
            xp[i] *= Y[i];
            xp[i] %= M[i];
            hash[i] -= dq.front() * xp[i];
            hash[i] %= M[i];
            if(hash[i] < 0)
                hash[i] += M[i];
        }
        dq.pop_front();
    }
    bool operator==(const RollingHash& rh){
        for(int i=0; i<3; ++i){
            if(hash[i] != rh.hash[i])
                return false;
        }
        return true;
    }
    bool operator!=(const RollingHash& rh){
        return !(*this == rh);
    }
};
const int RollingHash::X[] = {2000000011, 2000000033, 2000000063}; // 素数
const int RollingHash::Y[] = {1447368484, 1178571481, 1277777841}; // X * Y == 1 (mod M)
const int RollingHash::M[] = {2000000087, 2000000089, 2000000099}; // 合同式の法（素数）

int main()
{
    string s;
    cin >> s;
    int n = s.size();

    vector<int> v(6);
    v[0] = 0;
    v[2] = (n + 3) / 3;
    v[4] = v[2] * 2;
    v[1] = n - v[4];
    v[3] = v[2] + v[1];
    v[5] = n;
    vector<int> d = {0, -2, 1, -1, 2, 0};

    vector<RollingHash> rh(5);
    for(int i=0; i<5; ++i){
        for(int j=v[i]; j<v[i+1]; ++j){
            rh[i].push_back(s[j]);
        }
    }

    for(;;){
        bool ok = true;
        for(int i=0; i<3; ++i){
            if(rh[i] != rh[i+2])
                ok = false;
        }
        if(ok){
            cout << "Love " << s.substr(0, v[2]) << '!' << endl;
            return 0;
        }

        if(v[1] < 2)
            break;

        for(int i=1; i<5; ++i){
            if(d[i] > 0){
                for(int j=0; j<d[i]; ++j){
                    rh[i-1].push_back(s[v[i]]);
                    rh[i].pop_front();
                    ++ v[i];
                }
            }
            else{
                for(int j=0; j<-d[i]; ++j){
                    rh[i-1].pop_back();
                    rh[i].push_front(s[v[i]-1]);
                    -- v[i];
                }
            }
        }
    }

    cout << "mitomerarenaiWA" << endl;
    return 0;
}