LA --- 2965 Jurassic Remains 数相同的大写字母 【思维 + 状态压缩枚举 + 中途相遇法(折半搜索)】
2017-08-18 10:32
471 查看
传送门
//题意 : 给你n个由大写字母组成的字符串, 从中选取尽量多的串使得选中的串中出现了的大写字母的出现次数都是偶数. 输出可以选的最大值和具体选的那些串.
//思路 : 首先是思维转化, 我们发现一个大写字母出现了几次不重要, 出现的次数为奇数还是偶数才是比较重要的. 那么一个字母的状态无非就两种, 奇数或偶数, 那么我们就用二进制来表示, 1表示出现了奇数次, 0表示出现了偶数次, 如第二个样例 :
A B C D E F G
1 1 0 1 0 0 0 —ABD
0 0 0 0 1 0 1 —EG
0 0 0 0 1 0 1 —GE
1 1 0 0 1 0 0 —ABE
1 0 1 0 0 0 0 —AC
0 1 1 1 0 0 0 —BCD
所以现在问题转化为了从中选取尽量多的数使得他们的异或值为0, 注意异或值为0的一定是相同的两个数. 那么最简单的方法就是暴力O(2^n), 如果n达到了30左右肯定是不行的, 所以就用到了中途相遇法, 很神奇的, 也叫折半枚举, 即把n个串分成两堆, 那么我们分开进行二进制枚举, 先把上半部分所有可能的异或值全部求出来并标记, 然后以同样的方法求另一部分, 如果遇到了上面出现过的, 就更新答案. 这样是可以保证得的除答案的, 就算全部是选上方的, 枚举下面时我们也是枚举了0的情况的, 也就是全部都选上面的 , 所以这种方法就可行的. 并且复杂度降为O(√2^nlogn)这个复杂度是可以接受的.
AC Code
//重要的是学到中途相遇法的思想!!!
//题意 : 给你n个由大写字母组成的字符串, 从中选取尽量多的串使得选中的串中出现了的大写字母的出现次数都是偶数. 输出可以选的最大值和具体选的那些串.
//思路 : 首先是思维转化, 我们发现一个大写字母出现了几次不重要, 出现的次数为奇数还是偶数才是比较重要的. 那么一个字母的状态无非就两种, 奇数或偶数, 那么我们就用二进制来表示, 1表示出现了奇数次, 0表示出现了偶数次, 如第二个样例 :
A B C D E F G
1 1 0 1 0 0 0 —ABD
0 0 0 0 1 0 1 —EG
0 0 0 0 1 0 1 —GE
1 1 0 0 1 0 0 —ABE
1 0 1 0 0 0 0 —AC
0 1 1 1 0 0 0 —BCD
所以现在问题转化为了从中选取尽量多的数使得他们的异或值为0, 注意异或值为0的一定是相同的两个数. 那么最简单的方法就是暴力O(2^n), 如果n达到了30左右肯定是不行的, 所以就用到了中途相遇法, 很神奇的, 也叫折半枚举, 即把n个串分成两堆, 那么我们分开进行二进制枚举, 先把上半部分所有可能的异或值全部求出来并标记, 然后以同样的方法求另一部分, 如果遇到了上面出现过的, 就更新答案. 这样是可以保证得的除答案的, 就算全部是选上方的, 枚举下面时我们也是枚举了0的情况的, 也就是全部都选上面的 , 所以这种方法就可行的. 并且复杂度降为O(√2^nlogn)这个复杂度是可以接受的.
AC Code
/** @Cain*/ const int maxn=25+5; int a[maxn]; int n; int cal(int x) //算x的二进制表示中有多少个1. { int res = 0; while(x){ if(x&1) res++; x >>= 1; } return res; } void solve() { while(~scanf("%d",&n)){ string s; Fill(a,0); for(int i=0;i<n;i++){ cin >> s; for(int j=0;j<s.length();j++) a[i] ^= (1<<(s[j]-'A')); //printf("%d\n",a[i]); } //mp[x]表示的是异或值为x的并且个数尽量多组成的. 也就是i中1多的. map<int ,int >mp; int n1 = n/2,n2 = n-n1; for(int i=0;i<(1<<n1);i++){ int tmp = 0; for(int j=0;j<n1;j++){ if(i & (1<<j)) tmp ^= a[j]; } if(!mp[tmp] || cal(mp[tmp]) < cal(i)) mp[tmp] = i; } //分别枚举 int res = 0; for(int i=0;i<(1<<n2);i++){ int tmp = 0; for(int j=0;j<n2;j++){ if(i & (1<<j)) tmp ^= a[j+n1]; //注意是第二部分的. } if(mp[tmp] && cal(res) < (cal(mp[tmp]) + cal(i))) res = (i<<n1) ^ mp[tmp]; //为n1腾出空间, 所以是左移n1位!!! } int cnt = cal(res); printf("%d\n",cnt); int ans = 0; for(int i=0;i<n;i++) { if(res & (1<<i)){ //求出用了哪些串 ans++; printf("%d%c",i+1,ans == cnt ? '\n':' '); } } printf("\n"); } }
//重要的是学到中途相遇法的思想!!!
相关文章推荐
- UVALive - 2965 Jurassic Remains 状态压缩+中途相遇法
- 例题1.25 侏罗纪 Jurassic Remains UVALive - 2965 状态压缩 + 中途相遇法
- LA 2965 Jurassic Remains 中途相遇法 .
- LA 2965 - Jurassic Remains 中途相遇法
- LA 2965 Jurassic Remains (中途相遇法)
- LA 2965 Jurassic Remains / 中途相遇法
- POJ 1903 - Jurassic Remains 中途相遇法(枚举)
- POJ 1903 - Jurassic Remains 中途相遇法(枚举)
- UVa 1326 - Jurassic Remains(枚举子集+中途相遇法)
- CF contest 888 problem E 【思维 + 状压 + 中途相遇法(折半搜索)】
- Jurassic Remains UVALive - 2965(中途相遇法)
- 【UVALive】2965 Jurassic Remains 中途相遇法
- 【中途相遇+二进制】【NEERC 2003】Jurassic Remains
- poj 1903 Jurassic Remains 中途相遇法
- BAPC2014 K题 Key to Knowledge(中途相遇法,hash,状态压缩)
- problem/868/C Qualification Rounds 思维题 状态压缩 暴力枚举
- UVA 1326 Jurassic Remains 中途相遇法
- 折半搜索+状态压缩【P3067】 [USACO12OPEN]平衡的奶牛群Balanced Cow S…
- The Pilots Brothers' refrigerator(POJ 2965)(dfs枚举+状态压缩)
- 【中途相遇+二进制】【NEERC 2003】Jurassic Remains