답안 #617306

# 제출 시각 아이디 문제 언어 결과 실행 시간 메모리
617306 2022-08-01T10:41:35 Z Zanite Palinilap (COI16_palinilap) C++17
100 / 100
58 ms 26372 KB
#include <bits/stdc++.h>
using namespace std;

using ll	= long long;

const ll maxN	= 1e5 + 5;
const ll Alph	= 26;

#ifdef Zanite
	#define debug(x) cout << #x << " = " << x << '\n'
#else
	#define debug(x)
#endif

mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
ll getRand(ll l, ll r) {return uniform_int_distribution<ll>(l, r)(rng);}

const ll mod	= 1049433169;
ll madd(ll x, ll y) {x += y; if (x >= mod) x -= mod; return x;}
ll msub(ll x, ll y) {x -= y; if (x < 0) x += mod; return x;}
ll mmul(ll x, ll y) {x *= y; x %= mod; return x;}
ll modexp(ll x, ll y) {
	if (!x) return 0; if (!y) return 1;
	ll t = modexp(x, y >> 1);
	return mmul(t, mmul(t, ((y & 1ll) ? x : 1)));
}

ll key;
ll kpow[maxN], invkpow[maxN];

ll n;

void precomp() {
	key = getRand(1e5, 2e5);

	kpow[0] = invkpow[0] = 1;
	kpow[1] = key, invkpow[1] = modexp(key, mod-2);
	for (ll i = 1; i <= n; i++) {
		kpow[i] = mmul(kpow[i-1], kpow[1]);
		invkpow[i] = mmul(invkpow[i-1], invkpow[1]);
	}
}

struct HashString {
	ll fwd, bwd, len;

	HashString() {fwd = bwd = len = 0;}
	HashString(char c) {
		fwd = bwd = c - 'a';
		len = 1;
	}

	HashString operator + (const HashString &other) const {
		HashString ret = HashString();
		ret.fwd = madd(fwd, mmul(other.fwd, kpow[len]));
		ret.bwd = madd(mmul(bwd, kpow[other.len]), other.bwd);
		ret.len = len + other.len;
		return ret;
	}

	bool isPalindrome() {return (fwd == bwd);}
};

string S;
ll fwd[maxN], bwd[maxN];
ll odd[maxN], even[maxN];
ll change[maxN][Alph];
ll intersect[maxN];

ll getFwd(ll l, ll r) {return mmul(invkpow[l-1], msub(fwd[r], fwd[l-1]));}
ll getBwd(ll l, ll r) {return mmul(invkpow[n-r], msub(bwd[l], bwd[r+1]));}

void computeInitial() {
	// compute forwards and backwards hash
	for (ll i = 1; i <= n; i++) {
		fwd[i] = madd(fwd[i-1], mmul(S[i] - 'a', kpow[i-1]));
	}
	for (ll i = n; i >= 1; i--) {
		bwd[i] = madd(bwd[i+1], mmul(S[i] - 'a', kpow[n-i]));
	}

	// find the number of odd and even palindromes centered at i
	// for even palindromes, the index is the "left part of center"

	// compute intersect[i] := the number of polygons that involve character i
	// because we add slopes, this can be done with prefix prefix difference

	// also, for each center, find the first differing character
	// and find how many palindromes can be created by changing that character

	// odd
	for (ll i = 1; i <= n; i++) {
		ll l = 0, r = min(i-1, n-i), ans = -1;
		while (l <= r) {
			ll m = (l+r) >> 1;
			if (getFwd(i-m, i+m) == getBwd(i-m, i+m)) {
				ans = m;
				l = m + 1;
			} else {
				r = m - 1;
			}
		}
		odd[i] = ans+1;
		intersect[i-ans]++;
		intersect[i+1] -= 2;
		intersect[i+ans+2]++;

		//cout << i << " = " << ans+1 << '\n';

		//for (ll j = 1; j < maxN; j++) {cout << intersect[j] << ' ';} cout << '\n';

		// first different
		ll DL = i-ans-1, DR = i+ans+1;
		if (DL < 1 || DR > n) continue;

		//cout << "First different at " << DL << ' ' << DR << '\n';

		// extend palindrome
		l = 1, r = min(DL-1, n-DR), ans = 0;
		while (l <= r) {
			ll m = (l+r >> 1);
			if (getFwd(DL-m, DL-1) == getBwd(DR+1, DR+m)) {
				ans = m;
				l = m + 1;
			} else {
				r = m - 1;
			}
		}

		//cout << "Total change of " << ans+1 << '\n';

		change[DL][S[DR] - 'a'] += ans+1;
		change[DR][S[DL] - 'a'] += ans+1;
	}

	// even
	for (ll i = 1; i < n; i++) {
		ll l = 0, r = min(i-1, n-(i+1)), ans = -1;
		while (l <= r) {
			ll m = (l+r) >> 1;
			if (getFwd(i-m, i+m+1) == getBwd(i-m, i+m+1)) {
				ans = m;
				l = m + 1;
			} else {
				r = m - 1;
			}
		}
		even[i] = ans+1;
		intersect[i-ans]++;
		intersect[i+1]--;
		intersect[i+2]--;
		intersect[i+ans+3]++;

		//cout << i << " = " << ans+1 << '\n';

		//for (ll j = 1; j < maxN; j++) {cout << intersect[j] << ' ';} cout << '\n';

		// first different
		ll DL = i-ans-1, DR = i+ans+2;
		if (DL < 1 || DR > n) continue;

		//cout << "First different at " << DL << ' ' << DR << '\n';

		// extend palindrome
		l = 1, r = min(DL-1, n-DR), ans = 0;
		while (l <= r) {
			ll m = (l+r >> 1);
			if (getFwd(DL-m, DL-1) == getBwd(DR+1, DR+m)) {
				ans = m;
				l = m + 1;
			} else {
				r = m - 1;
			}
		}

		//cout << "Total change of " << ans+1 << '\n';

		change[DL][S[DR] - 'a'] += ans+1;
		change[DR][S[DL] - 'a'] += ans+1;
	}

	// restore the slope slope array as slope array and then as the array
	//for (ll j = 1; j < maxN; j++) {cout << intersect[j] << ' ';} cout << '\n';
	for (ll i = 1; i <= 2; i++) {
		for (ll j = 1; j < maxN; j++) {
			intersect[j] += intersect[j-1];
		}
		//for (ll j = 1; j < maxN; j++) {cout << intersect[j] << ' ';} cout << '\n';
	}
}

int main() {
	ios_base::sync_with_stdio(false); cin.tie(NULL);

	cin >> S;
	n = S.length();
	S = "#" + S;

	precomp();
	computeInitial();

	// calculate answer if we don't change anything
	ll ans = 0;
	for (ll i = 1; i <= n; i++) {
		ans += odd[i] + even[i];
	}
	debug(ans);

	// compute each possible action that we can take
	ll maxDiff = 0;
	for (ll i = 1; i <= n; i++) {
		for (ll nw = 0; nw < Alph; nw++) {
			//cout << "change[" << i << "][" << nw << "] = " << change[i][nw] << '\n';

			if (nw == S[i] - 'a') continue;

			// remove all palindromes with that character as a component, except for odd palindromes
			ll delta = -intersect[i] + odd[i];

			// add all palindromes that will be created
			delta += change[i][nw];

			maxDiff = max(maxDiff, delta);
		}
	}
	cout << ans + maxDiff << '\n';
}

Compilation message

palinilap.cpp: In function 'll modexp(ll, ll)':
palinilap.cpp:23:2: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
   23 |  if (!x) return 0; if (!y) return 1;
      |  ^~
palinilap.cpp:23:20: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
   23 |  if (!x) return 0; if (!y) return 1;
      |                    ^~
palinilap.cpp: In function 'void computeInitial()':
palinilap.cpp:121:13: warning: suggest parentheses around '+' inside '>>' [-Wparentheses]
  121 |    ll m = (l+r >> 1);
      |            ~^~
palinilap.cpp:167:13: warning: suggest parentheses around '+' inside '>>' [-Wparentheses]
  167 |    ll m = (l+r >> 1);
      |            ~^~
# 결과 실행 시간 메모리 Grader output
1 Correct 1 ms 1108 KB Output is correct
2 Correct 1 ms 1108 KB Output is correct
3 Correct 1 ms 1108 KB Output is correct
4 Correct 1 ms 1108 KB Output is correct
5 Correct 1 ms 1108 KB Output is correct
# 결과 실행 시간 메모리 Grader output
1 Correct 2 ms 2388 KB Output is correct
2 Correct 3 ms 2388 KB Output is correct
3 Correct 3 ms 2388 KB Output is correct
4 Correct 2 ms 1876 KB Output is correct
5 Correct 2 ms 2132 KB Output is correct
6 Correct 3 ms 2388 KB Output is correct
7 Correct 3 ms 2388 KB Output is correct
# 결과 실행 시간 메모리 Grader output
1 Correct 50 ms 26236 KB Output is correct
2 Correct 34 ms 26324 KB Output is correct
3 Correct 34 ms 26308 KB Output is correct
4 Correct 58 ms 26360 KB Output is correct
5 Correct 47 ms 26312 KB Output is correct
6 Correct 47 ms 26308 KB Output is correct
7 Correct 48 ms 26328 KB Output is correct
8 Correct 32 ms 5968 KB Output is correct
9 Correct 49 ms 26260 KB Output is correct
10 Correct 47 ms 26308 KB Output is correct
11 Correct 38 ms 26360 KB Output is correct
12 Correct 48 ms 26352 KB Output is correct
13 Correct 51 ms 26372 KB Output is correct
14 Correct 50 ms 26320 KB Output is correct
15 Correct 49 ms 26316 KB Output is correct
16 Correct 42 ms 26312 KB Output is correct
17 Correct 46 ms 26316 KB Output is correct
18 Correct 50 ms 26232 KB Output is correct
19 Correct 44 ms 26364 KB Output is correct