バイトの競プロメモ

主に競技プログラミング

D - Yet Another Palindrome Partitioning

https://atcoder.jp/contests/code-festival-2017-qualc/tasks/code_festival_2017_qualc_d

 

思考

回文の条件は奇数個のアルファベットが高々1つ

アルファベットはbitで持てる

いくつかの区間に分割するdpか、左から貪欲に取ればよさそう

貪欲は駄目だった

だから分割dp

 

dp[i] := iまでを分割するときの最小として

あるiについてi>jなるjで、j~iの区間が回文条件を満たしており、dp[j]が最小となる物が見つけられれば遷移できそう

 

zero sum rangesを連想した 

各アルファベットの差分で奇数となる物が高々一つならいい

つまりアルファベットの偶奇の累積和を取ればいい(bitで持てる)

bitで持てるのでbest[m] :=  累積(01)がmとなる場所の内、最小の分割数 とできる

 

遷移は現在地点の累積をmとして、偶奇が異なるbitを26通り試してやればいい

 

類題

https://atcoder.jp/contests/agc023/tasks/agc023_a

https://atcoder.jp/contests/agc031/tasks/agc031_b

 

https://atcoder.jp/contests/code-festival-2017-qualc/submissions/4799781

map<int,int> bes;
void solve() {
string s = sin();
n = sz(s);
minu(s, 'a');
//0 indexで考えられる
bes[0] = 0;
int m = 0;
int res = 0;//一番最後が答え
rep(i, n) {
m ^= bit(s[i]);
if (!bes.count(m))bes[m] = inf;
int lv = inf;
//全て偶数
chmi(lv, bes[m]);
//bが奇数
rep(b, 26) {
int tm = m ^bit(b);
if (!bes.count(tm))continue;
chmi(lv, bes[tm]);
}
if (i == n - 1)res = lv + 1;//右端なら必ず取る
else chmi(bes[m], lv + 1);
}

cout << res << endl;
}