zoukankan      html  css  js  c++  java
  • 【Atcoder】CODE FESTIVAL 2017 qual C D

    【题意】

    给定只含小写字母的字符串,要求分割成若干段使段内字母重组顺序后能得到回文串,求最少分割段数。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;
    }
  • 相关阅读:
    学习自建调试体系(二)
    寻找未导出函数的函数地址
    Http
    git忽略.gitignore
    Flask-sqlacodegen
    liunx速查
    BBS论坛项目
    vim操作
    部署
    python3 环境搭建
  • 原文地址:https://www.cnblogs.com/juruohx/p/7783677.html
Copyright © 2011-2022 走看看