UVA
来源:互联网 发布:macbook装windows教程 编辑:程序博客网 时间:2024/05/01 03:16
题意:
给你n 个串(仅包含 大写字母), 要求选择尽可能多的串,使得 所有的字母出现次数均为偶数次。
思路:
真的蜜汁题意, 比赛结束都没读懂。。。。
18s 时间很充足, 2^24 直接爆可以过。。
记录一下 折半搜索。
总共24个串, 暴力是2^ 24
我们可以先枚举前一半,把前一半的答案 存起来。 在枚举后一半 , 直接看对应的答案是否存在即可。
对于这个题, 我们可以把 26个字母出现次数,只用01 表示(因为我们只关心奇偶), 然后就可以压缩成一个二进制数了 。
对于每个26字母的状态, 我们存选择了哪n/2 个数, 也存成二进制即可。
这样复杂度变成了 2^ 12
#include <cstdio>#include <cstring>#include <algorithm>#include <queue>#include <vector>#include <iostream>#include <map>using namespace std;char s[30][100];map<int,int>mp;int cnt[30];int get(int x){ int ans = 0; while(x){ if (x & 1) ++ans; x >>= 1; } return ans;}int rev(int x,int n){ int ans = 0; for (int i = 0; i < n; ++i){ bool ok = x & (1<<i); ans = ans * 2 + ok; } return ans;}int main(){ int n; while(~scanf("%d",&n)){ for (int i = 0; i < n; ++i){ scanf("%s", s[i]); } mp.clear(); int n2 = n >> 1; for (int i = 0; i < (1<<n2); ++i){ memset(cnt,0,sizeof cnt); for (int j = 0; j < n2; ++j){ if (i & (1<<j)){ int len = strlen(s[j]); for (int k = 0; k < len; ++k){ cnt[s[j][k]-'A' ] ^= 1; } } } int v = 0; for (int j = 25; j >= 0; --j){ v = v * 2 + cnt[j]; } if (!mp.count(v)) mp[v] = rev(i, n2); else { int vv = mp[v]; if (get(vv) < get(i)) mp[v] = rev(i, n2); } } int ans1 = 0, ans2 = 0; int n1 = n - n2; for (int i = 0; i < (1<<n1); ++i){ memset(cnt,0,sizeof cnt); for (int j = 0; j < n1; ++j){ if (i & (1<<j)){ int id = n2 + j; int len = strlen(s[id]); for (int k = 0; k < len; ++k){ cnt[s[id][k]-'A' ] ^= 1; } } } int v = 0; for (int j = 25; j >= 0; --j){ v = v * 2 + cnt[j]; } int r = rev(i, n1); if (mp.count(v)){ int sum = get( (mp[v] << n1) | r ); if (sum > ans1){ ans1 = sum; ans2 = ( (mp[v] << n1) | r); } } } vector<int>sz; for (int i = n-1; i >= 0; --i){ if (ans2 & (1<<i)){ sz.push_back(n - i); } } printf("%d\n", sz.size()); sort(sz.begin(), sz.end()); for (int i = 0; i < sz.size(); ++i){ if (i)putchar(' '); printf("%d", sz[i]); } puts(""); } return 0;}