【题意】
给定只含小写字母的字符串,要求分割成若干段使段内字母重组顺序后能得到回文串,求最少分割段数。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; }
时间: 2024-10-13 07:23:32