답안 #46667

# 제출 시각 아이디 문제 언어 결과 실행 시간 메모리
46667 2018-04-22T14:14:41 Z ngkan146 회문 (APIO14_palindrome) C++11
73 / 100
1000 ms 59432 KB
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll mod = (ll) 1e9+9;
const ll base = 29;
int lg2[300005];
// remember to run this
void prepLg2(int bound){
    for(int i=2;i<=bound;i++)
        lg2[i] = lg2[i>>1] + 1;
}
struct suffixArray{
    vector <int> sa, saRank, tmp;
    vector <vector <int> > lcp;
    int strLen, gap;

    bool saCmp(int x,int y){
        if (saRank[x] != saRank[y])
            return saRank[x] < saRank[y];
        return x+gap < strLen && y+gap < strLen ? saRank[x+gap] < saRank[y+gap] : x > y;
    }

    void build_lcp(string &s){
        int k = 0;
        for(int i = 0; i < strLen; i ++){
            if (saRank[i] != strLen - 1){
                for (int j = sa[saRank[i] + 1]; max(i+k, j+k) < strLen && s[i + k] == s[j + k];)  ++k;
                lcp[saRank[i]][0] = k;
                if (k) k--;
            }
        }
        for(int k = 1; k < 20; k ++){
            for(int i = 0; i < strLen; i ++)
                if (i + (1<<k) < strLen)
                    lcp[i][k] = min(lcp[i][k-1], lcp[i+(1<<(k-1))][k-1]);
                else break;
        }
    }

    int getLcp(int l,int r){
        if (l > r)  swap(l, r);
        if (l == r) return strLen - sa[l];
        int k = lg2[r - l];
        return min(lcp[l][k], lcp[r-(1<<k)][k]);
    }

    void build(string &s, int isIndexFromOne = 0){
        strLen = s.size();
        sa.assign(strLen + 5, 0);
        saRank.assign(strLen + 5, 0);
        tmp.assign(strLen + 5, 0);
        lcp.assign(strLen + 5, vector<int>(20));
        //for(int i = 0; i < strLen; i ++)
        //    lcp[i].assign(20, 0);

        for(int i = 0; i < strLen; i ++)
            sa[i] = i, saRank[i] = s[i];

        for(gap = 1;;gap *= 2){
            sort(sa.begin(), sa.begin() + strLen, [&](int a, int b) {return this->saCmp(a, b);});
            //sort(sa.begin(), sa.begin() + strLen, saCmp);
            for(int i = 0; i < strLen; i ++) tmp[i+1] = tmp[i] + saCmp(sa[i], sa[i+1]);
            for(int i = 0; i < strLen; i ++) saRank[sa[i]] = tmp[i];
            if (tmp[strLen-1] == strLen-1) break;
        }
        build_lcp(s);
    }
};
int n;
string s[2];
suffixArray suff;
ll hashCode[2][300000], pBase[300000];
void prepHash(){
    pBase[0] = 1;
    for(int i=1;i<300000;i++)
        pBase[i] = pBase[i-1] * base % mod;

    hashCode[0][0] = s[0][0] - 'a' + 1;
    hashCode[1][0] = s[1][0] - 'a' + 1;
    for(int i=1;i<n;i++)
        hashCode[0][i] = (hashCode[0][i-1] + pBase[i] * (s[0][i] - 'a' + 1)) % mod,
        hashCode[1][i] = (hashCode[1][i-1] + pBase[i] * (s[1][i] - 'a' + 1)) % mod;
}
bool checkPalindrome(int l1,int r1){
    int l2 = n-1-r1;
    int r2 = n-1-l1;

    ll val1 = (hashCode[0][r1] - (l1 == 0 ? 0 : hashCode[0][l1-1]) + mod) % mod;
    ll val2 = (hashCode[1][r2] - (l2 == 0 ? 0 : hashCode[1][l2-1]) + mod) % mod;
    val1 = val1 * pBase[max(0, r2 - r1)] % mod;
    val2 = val2 * pBase[max(0, r1 - r2)] % mod;
    return val1 == val2;
}
ll ans = 0;
set <ll> mjk;
bool check(int root, int rad, bool type){
    //cout << root << ' ' << rad << ' ' << type << endl;
    if (type){
        if (!checkPalindrome(root-rad, root+rad))   return 0;
        ll val1 = (hashCode[0][root + rad] - (root - rad == 0 ? 0 : hashCode[0][root - rad -1]) + mod) % mod * pBase[n-1 - (root+rad)] % mod;
        if (mjk.count(val1))    return 0;
        mjk.insert(val1);
        int len = 2 * rad + 1;
        int head = suff.saRank[root-rad];
        int far = head;
        int near = head;

        for(int k=20;k>=0;k--){
            if (far + (1<<k) < n && suff.getLcp(head, far + (1<<k)) >= len)
                far += (1<<k);
        }
        for(int k=20;k>=0;k--){
            if (near - (1<<k) >= 0 && suff.getLcp(near - (1<<k), head) >= len)
                near -= (1<<k);
        }
        ans = max(ans, 1ll * len * (far - near + 1));
        return 1;
    }
    else{
        if (!checkPalindrome(root-1-rad, root+rad))   return 0;
        ll val1 = (hashCode[0][root + rad] - (root-1 - rad == 0 ? 0 : hashCode[0][root-1 - rad -1]) + mod) % mod * pBase[n-1 - (root+rad)] % mod;
        if (mjk.count(val1))    return 0;
        mjk.insert(val1);
        int len = 2 * (rad+1);
        int head = suff.saRank[root-1-rad];
        int far = head;
        int near = head;

        for(int k=20;k>=0;k--){
            if (far + (1<<k) < n && suff.getLcp(head, far + (1<<k)) >= len)
                far += (1<<k);
        }
        for(int k=20;k>=0;k--){
            if (near - (1<<k) >= 0 && suff.getLcp(near - (1<<k), head) >= len)
                near -= (1<<k);
        }
        ans = max(ans, 1ll * len * (far - near + 1));
    }
}
int main(){
    //freopen("47","r",stdin);
    prepLg2(300000);
    iostream::sync_with_stdio(0);
    cin >> s[0];
    n = s[0].size();

    s[1] = s[0];
    reverse(s[1].begin(), s[1].end());

    suff.build(s[0]);
    prepHash();

    for(int i=0;i<n;i++){
        // i is root
        int radiusL = 0, radiusR = n;
        while(radiusL+1 < radiusR){
            int mid = (radiusL + radiusR) / 2;
            if (i - mid < 0 || i + mid >= n)
                radiusR = mid;
            else if (checkPalindrome(i - mid, i + mid))
                radiusL = mid;
            else
                radiusR = mid;
        }
        int len = radiusL;
        while(len >= 0)
            if (!check(i, len, 1))  break;
            else -- len;
        if (!i) continue;

        radiusL = 0, radiusR = n;
        while(radiusL+1 < radiusR){
            int mid = (radiusL + radiusR) / 2;
            if (i-1 - mid < 0 || i + mid >= n)
                radiusR = mid;
            else if (checkPalindrome(i-1 - mid, i + mid))
                radiusL = mid;
            else
                radiusR = mid;
        }
        len = radiusL;
        while(len >= 0)
            if (!check(i, len, 0))  break;
            else -- len;
    }
    cout<< ans << endl;
}

Compilation message

palindrome.cpp: In function 'bool check(int, int, bool)':
palindrome.cpp:139:1: warning: control reaches end of non-void function [-Wreturn-type]
 }
 ^
# 결과 실행 시간 메모리 Grader output
1 Correct 8 ms 3832 KB Output is correct
2 Correct 6 ms 3944 KB Output is correct
3 Correct 6 ms 4120 KB Output is correct
4 Correct 8 ms 4120 KB Output is correct
5 Correct 7 ms 4120 KB Output is correct
6 Correct 7 ms 4168 KB Output is correct
7 Correct 6 ms 4168 KB Output is correct
8 Correct 6 ms 4168 KB Output is correct
9 Correct 6 ms 4168 KB Output is correct
10 Correct 6 ms 4168 KB Output is correct
11 Correct 8 ms 4168 KB Output is correct
12 Correct 7 ms 4168 KB Output is correct
13 Correct 6 ms 4168 KB Output is correct
14 Correct 6 ms 4168 KB Output is correct
15 Correct 6 ms 4168 KB Output is correct
16 Correct 6 ms 4168 KB Output is correct
17 Correct 6 ms 4168 KB Output is correct
18 Correct 6 ms 4168 KB Output is correct
19 Correct 6 ms 4168 KB Output is correct
20 Correct 6 ms 4168 KB Output is correct
21 Correct 6 ms 4168 KB Output is correct
22 Correct 6 ms 4168 KB Output is correct
23 Correct 6 ms 4168 KB Output is correct
24 Correct 6 ms 4168 KB Output is correct
25 Correct 7 ms 4196 KB Output is correct
26 Correct 7 ms 4196 KB Output is correct
27 Correct 7 ms 4196 KB Output is correct
28 Correct 6 ms 4196 KB Output is correct
29 Correct 6 ms 4196 KB Output is correct
30 Correct 6 ms 4204 KB Output is correct
31 Correct 6 ms 4204 KB Output is correct
32 Correct 7 ms 4204 KB Output is correct
# 결과 실행 시간 메모리 Grader output
1 Correct 8 ms 4348 KB Output is correct
2 Correct 7 ms 4348 KB Output is correct
3 Correct 8 ms 4348 KB Output is correct
4 Correct 9 ms 4348 KB Output is correct
5 Correct 8 ms 4348 KB Output is correct
6 Correct 8 ms 4348 KB Output is correct
7 Correct 7 ms 4348 KB Output is correct
8 Correct 7 ms 4348 KB Output is correct
9 Correct 7 ms 4348 KB Output is correct
10 Correct 7 ms 4348 KB Output is correct
11 Correct 8 ms 4348 KB Output is correct
12 Correct 8 ms 4348 KB Output is correct
# 결과 실행 시간 메모리 Grader output
1 Correct 28 ms 6012 KB Output is correct
2 Correct 29 ms 6140 KB Output is correct
3 Correct 28 ms 6140 KB Output is correct
4 Correct 28 ms 6140 KB Output is correct
5 Correct 34 ms 6272 KB Output is correct
6 Correct 30 ms 6272 KB Output is correct
7 Correct 27 ms 6272 KB Output is correct
8 Correct 15 ms 6272 KB Output is correct
9 Correct 16 ms 6272 KB Output is correct
10 Correct 27 ms 6272 KB Output is correct
# 결과 실행 시간 메모리 Grader output
1 Correct 376 ms 23616 KB Output is correct
2 Correct 352 ms 23632 KB Output is correct
3 Correct 375 ms 23636 KB Output is correct
4 Correct 407 ms 23760 KB Output is correct
5 Correct 606 ms 23760 KB Output is correct
6 Correct 480 ms 23760 KB Output is correct
7 Correct 423 ms 23760 KB Output is correct
8 Correct 121 ms 23760 KB Output is correct
9 Correct 223 ms 23760 KB Output is correct
10 Correct 433 ms 23760 KB Output is correct
# 결과 실행 시간 메모리 Grader output
1 Execution timed out 1085 ms 59432 KB Time limit exceeded
2 Halted 0 ms 0 KB -