UVa LA 2965 - Jurassic Remains 中间相遇,状态简化 难度: 2
题目
https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=966
题意
n个大写字母串(n <= 24),问最多取多少个,使得所有字符出现的次数都是偶数。
思路
如刘书
1. 由于最多出现26个字母,而且字母在字符串中出现的次数本身不重要,只要记录奇偶性,所以可以将这些字符串转化为01串便于存储。
2. 问题转化为最多取多少个01串,使得其异或结果为0
3. 这样就可以用2^24来枚举,但这样状态还是太多了
4. 问题可以转化为前n/2个字符串子集组成的异或结果与后n/2个字符串子集组成的异或结果相同的情况下,最多取多少个字符串。
感想
1. 一开始忘了字符串本身可能存在重复的字符串
2. 之后忘了程序会修改pos
代码
#include <algorithm> #include <cassert> #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <map> #include <queue> #include <set> #include <string> #include <tuple> #define LOCAL_DEBUG using namespace std; const int MAXN = 24; int n; int a[MAXN]; int staStack[1 << MAXN]; int posStack[1 << MAXN]; int bone2sta(char * str) { int sta = 0; for (char * p = str; *p != 0; p++) { sta ^= 1 << (*p - 'A'); } return sta; } int getDigitCnt(int x) { int ans = 0; while (x > 0) { x -= (x & -x); ans++; } return ans; } int main() { #ifdef LOCAL_DEBUG freopen("C:\\Users\\Iris\\source\\repos\\ACM\\ACM\\input.txt", "r", stdin); freopen("C:\\Users\\Iris\\source\\repos\\ACM\\ACM\\output.txt", "w", stdout); #endif // LOCAL_DEBUG //int T; // scanf("%d", &T); for (int ti = 1;scanf("%d", &n) == 1 && n; ti++) { for (int i = 0; i < n; i++) { char buff[27]; scanf("%s", buff); a[i] = bone2sta(buff); } int half_n = n / 2; map<int, int> sta2pos; sta2pos[0] = 0; int staCnt = 0; staStack[staCnt++] = 0; for (int i = 0; i < half_n; i++) { for (int j = staCnt - 1; j >= 0; j--) { posStack[j] = sta2pos[staStack[j]]; } for (int j = staCnt - 1; j >= 0; j--) { int sta = staStack[j]; int pos = posStack[j]; int newSta = sta ^ a[i]; int newPos = pos | (1 << i); if (sta2pos.count(newSta) == 0) { sta2pos[newSta] = newPos; staStack[staCnt++] = newSta; } else { int oldDigitCnt = getDigitCnt(sta2pos[newSta]); int newDigitCnt = getDigitCnt(pos) + 1; if(newDigitCnt > oldDigitCnt)sta2pos[newSta] = newPos; } } } map<int, int> othersta2pos; othersta2pos[0] = 0; staCnt = 0; staStack[staCnt++] = 0; for (int i = half_n; i < n; i++) { for (int j = staCnt - 1; j >= 0; j--) { posStack[j] = othersta2pos[staStack[j]]; } for (int j = staCnt - 1; j >= 0; j--) { int sta = staStack[j]; int pos = posStack[j]; int newSta = sta ^ a[i]; int newPos = pos | (1 << i); if (othersta2pos.count(newSta) == 0) { othersta2pos[newSta] = newPos; staStack[staCnt++] = newSta; } else { int oldDigitCnt = getDigitCnt(othersta2pos[newSta]); int newDigitCnt = getDigitCnt(pos) + 1; if (newDigitCnt > oldDigitCnt)othersta2pos[newSta] = newPos; } } } int ans = 0, ansPos = 0; for (int j = 0; j < staCnt; j++) { int sta = staStack[j]; if (sta2pos.count(sta) != 0) { int digitCnt = getDigitCnt(sta2pos[sta]) + getDigitCnt(othersta2pos[sta]); if (digitCnt > ans) { ans = digitCnt; ansPos = sta2pos[sta] | othersta2pos[sta]; } } } printf("%d\n", ans); for (int i = 0; i < n; i++) { if (ansPos & (1 << i)) { printf("%d ", i + 1); } } puts(""); } return 0; }