uvalive 2965 Jurassic Remains

https://vjudge.net/problem/UVALive-2965

 题意:

给出若干个由大写字母组成的字符串,要求选出尽量多的字符串,使得每个大写字母出现的次数是偶数。

思路:

如果说我们把每个字母映射为不同的数字,那么每个字符串就可以用不同的数字来表示,即按照二进制位转化各个字符。

如ABCD既可以表示为1111,ABCE可以表示为11101。

那么问题就转化成了给出n个数字,那么选择尽量多的数字使得他们的异或为0(每个字符出现偶数次,则他们的异或肯定为0)。

一开始我直接用的2^N的状态压缩但是t了,参考了训练指南,之后复杂度降为1.414^(N) * log(N)。

先把前n/2个数可以得到的数字用一个map存起来,之后枚举后面n - n/2个数可以得到的结果,直接在map里面寻找位数尽量大的就可以了。

求一个数的二进制位有多少个1,这题十分巧妙的用了二分。

代码:

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <vector>
 4 #include <map>
 5 using namespace std;
 6 
 7 int a[30];
 8 
 9 vector<int> rec;
10 map<int,int> mmp;
11 
12 int calbit(int x)
13 {
14     if (x == 0) return 0;
15 
16     return calbit(x / 2) + (x & 1);
17 }
18 
19 int main()
20 {
21     int n;
22 
23     while (scanf("%d",&n) != EOF)
24     {
25         mmp.clear();
26         rec.clear();
27 
28         for (int i = 0;i < n;i++)
29         {
30             int tmp = 0;
31 
32             char b[30];
33 
34             scanf("%s",b);
35 
36             for (int j = 0;j < strlen(b);j++)
37             {
38                 tmp ^= (1 << (b[j] - 'A'));
39             }
40 
41             a[i] = tmp;
42         }
43 
44         int n1 = n / 2;
45         int n2 = n - n1;
46 
47         for (int i = 0;i < (1 << n1);i++)
48         {
49             int tmp = 0;
50 
51             for (int j = 0;j < n1;j++)
52             {
53                 if (i & (1 << j)) tmp ^= a[j];
54             }
55 
56             if (mmp.find(tmp) != mmp.end() || calbit(mmp[tmp]) < calbit(i)) mmp[tmp] = i;
57         }
58 
59         int ans = 0;
60 
61         for (int i = 0;i < (1 << n2);i++)
62         {
63             int tmp = 0;
64 
65             for (int j = 0;j < n2;j++)
66             {
67                 if (i & (1 << j)) tmp ^= a[n1+j];
68             }
69 
70             if (mmp.find(tmp) != mmp.end())
71             {
72                 if (calbit(i) + calbit(mmp[tmp]) > calbit(ans)) ans = mmp[tmp] ^ (i << n1);
73             }
74         }
75 
76         for (int i = 0;i < n;i++)
77         {
78             if (ans & (1 << i)) rec.push_back(i);
79         }
80 
81         printf("%d\n",rec.size());
82 
83         for (int i = 0;i < rec.size();i++)
84         {
85             printf("%d%c",rec[i] + 1,i == rec.size() ? '\n': ' ');
86         }
87 
88         printf("\n");
89     }
90 
91     return 0;
92 }

 

posted @ 2017-10-16 17:48  qrfkickit  阅读(148)  评论(0编辑  收藏  举报