Submission #1362971

#TimeUsernameProblemLanguageResultExecution timeMemory
1362971NikoBaoticPalinilap (COI16_palinilap)C++20
100 / 100
270 ms42716 KiB
#include "bits/stdc++.h"

using namespace std;

typedef long long ll;
typedef pair<ll, ll> pii;

#define all(x) x.begin(), x.end()
#define sz(x) ((int) ((x).size()))
#define pb push_back
#define F first
#define S second
#define FIO ios_base::sync_with_stdio(false); cin.tie(0)

struct Seg {
	const static int off = 1 << 17;

	ll tr[off * 2];
	ll le[off * 2];
	ll p[off * 2];

	Seg() {
		memset(tr, 0, sizeof tr);
		memset(le, 0, sizeof le);
		memset(p, 0, sizeof p);
	}

	void prop(int node, int x, int y) {
		tr[node] += le[node] * (y - x + 1) + (y - x + 1) * (y - x + 2) / 2 * p[node];

		if (x != y) {
			p[node * 2] += p[node];
			p[node * 2 + 1] += p[node];
			le[node * 2] += le[node];
			le[node * 2 + 1] += le[node] + (y - x + 1) / 2 * p[node];
		}

		le[node] = 0;
		p[node] = 0;
	}

	void update(int l, int r, int node = 1, int x = 0, int y = off - 1) {
		prop(node, x, y);

		if (l > y or x > r) return;
		if (l <= x and y <= r) {
			p[node] += 1;
			le[node] += x - l;	
			prop(node, x, y);
			return;
		}

		update(l, r, node * 2, x, (x + y) / 2);
		update(l, r, node * 2 + 1, (x + y) / 2 + 1, y);
		
		tr[node] = tr[node * 2] + tr[node * 2 + 1];
	}

	ll query(int l, int r, int node = 1, int x = 0, int y = off - 1) {
		if (l > y or x > r) return 0;
		prop(node, x, y);
		if (l <= x and y <= r) return tr[node];

		return query(l, r, node * 2, x, (x + y) / 2) + query(l, r, node * 2 + 1, (x + y) / 2 + 1, y);
	}

	void updatei(int l, int r) {
		update(off - r - 1, off - l - 1);
	}

	ll queryi(int l, int r) {
		return query(off - r - 1, off - l - 1);
	}
};

const int N = 1e5 + 10;
const int K = 30;
const int MOD1 = 1e9 + 7;
const int MOD2 = 1e9 + 9;
const int B1 = 31337;
const int B2 = 67;

ll potM(ll x, ll k, ll MOD) { if (k == 0) return 1; ll a = potM(x, k / 2, MOD); if (k % 2 == 0) { return (a * a) % MOD; } else { return ((a * a) % MOD * x) % MOD; }}

string s;
ll pot1[N];
ll pot2[N];
ll inv1[N];
ll inv2[N];
ll h1[N][2];
ll h2[N][2];
ll imp[N][K];
ll cur;
Seg u, ui;

pii hp(int l, int r) {
	return {(h1[r + 1][0] - h1[l][0] + MOD1) % MOD1 * inv1[l] % MOD1, (h2[r + 1][0] - h2[l][0] + MOD2) % MOD2 * inv2[l] % MOD2};
}

pii hs(int l, int r) {
	swap(l, r);
	l = sz(s) - l - 1;
	r = sz(s) - r - 1;

	return {(h1[r + 1][1] - h1[l][1] + MOD1) % MOD1 * inv1[l] % MOD1, (h2[r + 1][1] - h2[l][1] + MOD2) % MOD2 * inv2[l] % MOD2};
}

int find(int c1, int c2) {
	int l = 0;
	int r = sz(s);

	while (l < r) {
		int mid = (l + r) / 2;

		if (c1 - mid < 0 or c2 + mid >= sz(s) or hp(c1 - mid, c1) != hs(c2, c2 + mid)) {
			r = mid;
		} else {
			l = mid + 1;
		}
	}

	return l;
}

void run(int c1, int c2) {
	int cnt = find(c1, c2);

	if (cnt != 0) {
		if (c1 == c2) {
			if (cnt != 1) {
				ui.updatei(c2 + 1, c2 + cnt - 1);
				u.update(c1 - cnt + 1, c1 - 1);
			}
		} else {
			ui.updatei(c2, c2 + cnt - 1);
			u.update(c1 - cnt + 1, c1);
		}
	}

	cur += cnt;

	if (c1 - cnt >= 0 and c2 + cnt < sz(s)) {
		imp[c1 - cnt][s[c2 + cnt] - 'a'] += find(c1 - cnt - 1, c2 + cnt + 1) + 1;
		imp[c2 + cnt][s[c1 - cnt] - 'a'] += find(c1 - cnt - 1, c2 + cnt + 1) + 1;
	}
}

int main() {
	FIO;

	pot1[0] = 1;
	pot2[0] = 1;
	inv1[0] = 1;
	inv2[0] = 1;

	for (int i = 1; i < N; i++) {
		pot1[i] = (pot1[i - 1] * B1) % MOD1;
		pot2[i] = (pot2[i - 1] * B2) % MOD2;

		inv1[i] = potM(pot1[i], MOD1 - 2, MOD1);
		inv2[i] = potM(pot2[i], MOD2 - 2, MOD2);
	}
	
	cin >> s;

	for (int i = 0; i < sz(s); i++) {
		h1[i + 1][0] = (h1[i][0] + pot1[i] * s[i]) % MOD1;
		h2[i + 1][0] = (h2[i][0] + pot2[i] * s[i]) % MOD2;
	}
	
	for (int i = 0; i < sz(s); i++) {
		h1[i + 1][1] = (h1[i][1] + pot1[i] * s[sz(s) - i - 1]) % MOD1;
		h2[i + 1][1] = (h2[i][1] + pot2[i] * s[sz(s) - i - 1]) % MOD2;
	}

	for (int i = 0; i < sz(s); i++) {
		run(i, i);
		if (i + 1 < sz(s)) run(i, i + 1);
	}

	ll be = 0;

	for (int i = 0; i < sz(s); i++) {
		ll mi = -u.query(i, i) - ui.queryi(i, i);

		for (int j = 0; j < K; j++) {
			be = max(be, mi + imp[i][j]);
		}
	}

	cout << cur + be << "\n";

	return 0;
}
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...