【Atcoder】CODE FESTIVAL 2017 qual C D - Yet Another Palindrome Partitioning

【题意】

给定只含小写字母的字符串,要求分割成若干段使段内字母重组顺序后能得到回文串,求最少分割段数。n<=2*10^5

【题解】

关键在于快速判断一个字符子串是否合法,容易发现合法仅当不存在或只存在一个奇数字符,其余字符均为偶数。

当涉及到奇偶性(%2)时,很自然能想到异或。

将小写字母a~z转化2^0~2^25,那么一个字符子串合法当且仅当其连续异或值是0或2^i(0<=i<=25)

令f[i]表示前i个合法的最少段数,sum[i]表示异或前缀和,则有:

f[i]=min(f[j])+1,sum[i]^sum[j]=0||2^i,也就是在前面所有合法的j中取最小的f[j]。

将合法条件移项,得到sum[i]^(0||2^i)=sum[j],那么对于当前的i,可以快速算出需要的sum[j]。

而sum值只有2*10^5个,可以用map存起来,然后就可以快速取用。

或者sum值本身不大,根据题目空间直接开数组也没问题。

复杂度O(26*n)。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 200000 + 50;
char a[maxn];
int f[maxn], sum[1 << 26];
int main(){
	scanf("%s", a + 1); int n = strlen(a + 1);
	memset(sum, 0x3f, sizeof(sum));
	int g = 0;
	f[0] = 0; sum[0] = 0;
	for (int i = 1; i <= n; ++i){
		int x = 1 << (a[i] - 'a');
		g ^= x;
		f[i] = sum[g];
		for (int j = 0; j < 26; ++j) f[i] = min(sum[g ^ (1 << j)], f[i]);
		++ f[i];
		sum[g] = min(sum[g], f[i]);
	}
	cout << f[n] << endl;
	return 0;
}
posted @ 2017-11-04 16:19  Iamhx  阅读(238)  评论(0编辑  收藏  举报