Submission #1242009

#TimeUsernameProblemLanguageResultExecution timeMemory
1242009Mike_VuPalinilap (COI16_palinilap)C++17
0 / 100
62 ms26032 KiB
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double dou;
#define pii pair<int, int>
#define fi first
#define se second
#define pb push_back
#define BITJ(x, j) (((x)>>(j))&1)
#define MASK(j) (1LL<<(j))
#define ALL(v) v.begin(), v.end()

template<typename T> bool maximize(T &x, const T &y) {
    if (x < y) {x = y; return 1;}
    return 0;
}
template<typename T> bool minimize(T &x, const T &y) {
    if (x > y) {x = y; return 1;}
    return 0;
}

namespace modulofunc{
    const int mod = 998244353;
    int add(int x, int y) {
        return (mod-x <= y ? x-mod+y : x+y);
    }
    void addt(int &x, int y) {
        x = add(x, y);
    }
    int sub(int x, int y) {
        return (x-y < 0 ? x-y+mod : x-y);
    }
    void subt(int &x, int y) {
        x = sub(x, y);
    }
    int mul(int x, int y) {
        return 1LL*x*y%mod;
    }
    int binpow(int x, int k) {
        int res = 1;
        while (k > 0 ){
            if (k&1) res = mul(res, x);
            x = mul(x, x);
            k >>= 1;
        }
        return res;
    }
}
using namespace modulofunc;

const int maxn = 1e5+5;
int n;
string s;

namespace sub3{
    const int base = 31;
    int pw[maxn], prefh[maxn][2];
    void setup() {
        pw[0] = 1;
        for (int i= 1; i < maxn; i++) {
            pw[i] = mul(pw[i-1], base);
//            if (i < 7) cout << pw[i] << ' ';
        }
//        cout << "\n";
        prefh[0][0] = 0;
        for (int i = 1; i <= n; i++) {
            prefh[i][0] = add(mul(prefh[i-1][0], base), (int)(s[i]-'a'+1));
        }
        prefh[n+1][1] = 0;
        for (int i = n; i; i--) {
            prefh[i][1] = add(mul(prefh[i+1][1], base), (int)(s[i]-'a'+1));
        }
//        cout << "here comes all prefh\n";
//        for (int i = 1; i <= n; i++) {
//            cout << prefh[i][0] << ' ';
//        }
//        cout << "\n";
//        for (int i = 1; i <= n; i++) {
//            cout << prefh[i][1] << ' ';
//        }
//        cout << "\n";
    }
    int gethash(int l, int r, bool rev) {
        int val;
        if (rev) val = sub(prefh[l][1], mul(prefh[r+1][1], pw[r-l+1]));
        else val = sub(prefh[r][0], mul(prefh[l-1][0], pw[r-l+1]));
//        cout << "gethash " << l << ' ' << r << ' ' << rev << ": " << val << "\n";
        return val;
    }

    struct segment{
        int l, r;
        bool inmid;
        segment(int _l, int _r, bool _inmid) {
            l = _l;
            r = _r;
            inmid = _inmid;
        }
    };
    vector<segment> realseg;
    ll incdelta[maxn], stadelta[maxn]; //delta encoding
    ll preans;
    ll anschange[maxn][26];
    ll ans;
    void construct_boundaries() {
        //setup boundaries
        //also calculate preans
        preans = 0;
        for (int i = 1; i <= n; i++) {
            //on element
            //bound of starting segment would be the mid
            int len = 0;
            for (int cnt = n>>1; cnt > 0; cnt >>= 1 ){
                while (len+cnt <= min(n-i, i-1) &&
                       gethash(i-(len+cnt), i, 1) == gethash(i, i+(len+cnt), 0)) {
                    len += cnt;
                }
            }
            //segments: i-len, i+len
            realseg.pb(segment(i-len, i+len, 0));
            preans += len+1;
//            cout << "on ele " << i << ' ' << len+1 << "\n";
        }
        for (int i = 1; i < n; i++) {
            //in mid
            int len = 0;
            for (int cnt = n>>1; cnt > 0; cnt >>= 1) {
                while (cnt+len <= min(i, n-i) &&
                       gethash(i-(len+cnt)+1, i, 1) == gethash(i+1, i+(len+cnt), 0)) {
                    len += cnt;
               }
            }
            //segment: i-len+1, i+len
            realseg.pb(segment(i-len+1, i+len, 1));
            preans += len;
//            cout << "in mid " << i << ' ' << len << "\n";
        }
        ans = preans;
    }
    int check_further(int l, int r) {
        if (l < 1 || r > n) return 0;
        int len = 0;
        for (int cnt = n>>1; cnt > 0; cnt >>= 1){
            while (len+cnt <= min(l, n-r+1) &&
                   gethash(l-(len+cnt)+1, l, 1) == gethash(r, r+(len+cnt)-1, 0)) {
                len += cnt;
           }
        }
        return len;
    }
    void solve() {
        setup();
        construct_boundaries();
        memset(anschange, 0, sizeof(anschange));
        memset(incdelta, 0, sizeof(incdelta));
        memset(stadelta, 0, sizeof(stadelta));
        //case add
        for (segment cur : realseg) {
            int l = cur.l, r = cur.r;
            //delta encoding
            int mid = (l+r)>>1;
            if (cur.inmid) {
                if (r-l > 0) {
                    //inmid
                    incdelta[l-1]++;
                    incdelta[mid]--;
                    incdelta[mid+1]--;
                    incdelta[r]++;
                }
            }
            else if (r-l > 1) {
                //in ele
                //->0<-
                incdelta[l-1]++;
                incdelta[mid-1]--;
                stadelta[mid-1] = l-mid;
                stadelta[mid] = mid-l;
                incdelta[mid+1]--;
                incdelta[r]++;
            }
            //eligible
            if (l <= 1 || r >= n) continue;
            //change left
            //change right
            int val = check_further(l-2, r+2)+1;
//            cout << "[] segment " << l << ' ' << r << ' ' << val << "\n";
            anschange[l-1][s[r+1]-'a'] += val;
            anschange[r+1][s[l-1]-'a'] += val;
        }
        //case minus
        //resolve encoding to ans
        ll curcou = 0, curinc = incdelta[0];
        for (int i = 1; i <= n; i++) {
            curcou += curinc;
            //fixed for i
            for (int c = 0; c < 26; c++) {
                anschange[i][c] -= curcou;
                //maximize ans
                maximize(ans, preans + anschange[i][c]);
            }
            curcou += stadelta[i];
            curinc += incdelta[i];
        }
        cout << ans;
    }
}

int main() {
    ios_base::sync_with_stdio(0);
    cin.tie(0);
//    #define name "task"
//    if (fopen(name".inp", "r")) {
//        freopen(name".inp", "r", stdin);
//        freopen(name".out", "w", stdout);
//    }
    cin >> s;
    n = (int)s.size();
    s = "#"+s;
    return sub3::solve(), 0;
}
/*
aaaa
10

baccb
9

slavko
7
*/
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...