uvalive2965(状态压缩)

来源:互联网 发布:淘宝店铺开设条件 编辑:程序博客网 时间:2024/06/15 03:36

题意:
给出n个由大写字母组成的串;
要求选出最多个数的串,并且每个字母个数是偶数;


思路:
我们只需要祖母个数是偶数,并不需要知道字母几个,所以我们用二进制来代表奇偶性就行了,这里用到状态压缩;
这里我们要用到两种状态,一种状态是选择状态,代表哪些字符串是被选中的,还有一种是结果状态,就是这样选择后,字母'A'~'Z'的奇偶型;
刚开始我枚举所有的状态,但是超时了;
看了题解发现,是要把n分成前一半和后一半两个部分;
我们知道两个数字异或完要等于0,那么必须两个数字完全一样;所以我们可以枚举前一半字符串所有选择状态,并看看这种选择状态下达到的结果状态,可能有很多种选择状态可以得到同一种结果状态,那么我们选最长的一个(就是选择状态中1最多的)
然后我们开始枚举后一半的选择状态,如果这种状态所达成的结果状态是在之前一半时有出现过的,那说明这个可以,只要前后两半的结果状态一样,异或完肯定是0,也就是全部是偶数,我们选其中最长的就行了;
输出是输出结果中1的个数;
并把结果中1对应的位置输出来;



#include<cstdio>#include<cstring>#include<algorithm>#include<map>using namespace std;map<int ,int> m;int Bit[25];char str[1000];int n;int countnum(int x) {return x == 0 ? 0 : countnum(x / 2) + (x & 1);}int main() {while(scanf("%d",&n) != EOF) {int ans = 0;memset(Bit, 0, sizeof(Bit));for(int i = 0; i < n; i++) {scanf("%s",str);for(int j = 0; str[j] != '\0'; j++){Bit[i] ^=  (1 << (str[j] - 'A'));}}m.clear();int n1 = n / 2;int n2 = n - n1;for(int i = 0; i < (1 << n1); i++) {int sta = 0;for(int j = 0 ; j < n ;j++) {if((1 << j) & i)sta ^= Bit[j];}if(!m.count(sta) ||countnum(m[sta]) < countnum(i))m[sta] = i;}for(int i = 0; i < (1 << n2) ;i++) {int sta = 0;for(int j = 0; j < n2; j++) {if(i & (1 << j))sta ^= Bit[n1 + j];}if(m.count(sta) && countnum(m[sta]) + countnum(i) > countnum(ans)) {ans = (i << n1) ^ m[sta];}}printf("%d\n",countnum(ans));bool f = true;for(int i = 0; i < n; i++) {if(ans & (1 << i)) {if(f) {printf("%d",i + 1);f = false;}elseprintf(" %d",i + 1);}}printf("\n");}}


0 0