zoukankan      html  css  js  c++  java
  • NEERC2003 Jurassic Remains 侏罗纪

    传送


    题面:给定(n(nleqslant 26))个只有大写字母的字符串,选择尽量多的串,使得每个大写字母都出现偶数次。


    对于每个字母,我们不关注他的出现次数,只关心是奇是偶,而因为大写字母只有'A'~'Z'26个,所以我们可以用一个整数(a_i)表示第(i)个字符串中某一个字母出现情况,这一位是0就表示偶数次,是1就是奇数次。
    预处理这些后,如果暴力,那就是(O(2^{26}))。这时候就可以用折半搜索把复杂度降低到(O(2^{n/2}log n)=O(2^{13}log n)),此题就解决了。


    代码虽然好写,但是有一处我一直不明白为什么换一种写法就过不去,详见代码吧。

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<vector>
    #include<queue>
    #include<map> 
    #include<assert.h>
    #include<ctime>
    using namespace std;
    #define enter puts("") 
    #define space putchar(' ')
    #define Mem(a, x) memset(a, x, sizeof(a))
    #define In inline
    #define forE(i, x, y) for(int i = head[x], y; ~i && (y = e[i].to); i = e[i].nxt)
    typedef long long ll;
    typedef double db;
    const int INF = 0x3f3f3f3f;
    const db eps = 1e-8;
    const int maxn = 1e3 + 5;
    In ll read()
    {
    	ll ans = 0;
    	char ch = getchar(), las = ' ';
    	while(!isdigit(ch)) las = ch, ch = getchar();
    	while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
    	if(las == '-') ans = -ans;
    	return ans;
    }
    In void write(ll x)
    {
    	if(x < 0) x = -x, putchar('-');
    	if(x >= 10) write(x / 10);
    	putchar(x % 10 + '0');
    }
    In void MYFILE()
    {
    #ifndef mrclr
    	freopen("jurassic.in", "r", stdin);
    	freopen("jurassic.out", "w", stdout);
    #endif
    }
    
    int n, a[maxn];
    char s[maxn];
    struct Node{int S, num;};
    map<int, Node> mp;
    
    int main()
    {
    	MYFILE();
    	n = read();
    	for(int i = 1; i <= n; ++i)
    	{
    		scanf("%s", s);
    		int len = strlen(s); a[i] = 0;
    		for(int j = 0; j < len; ++j) a[i] ^= (1 << (s[j] - 'A'));
    	}
    	int n1 = n / 2, n2 = n - n1;
    	for(int i = 0; i < (1 << n1); ++i)
    	{
    		int num = 0, S = 0;
    		for(int j = 0; j < n1; ++j)
    			if((i >> j) & 1) ++num, S ^= a[j + 1];
    		if(num > mp[S].num) mp[S] = (Node){i, num};
    	}
    	Node Ans; Ans.num = Ans.S = 0;
    	for(int i = 0; i < (1 << n2); ++i)
    	{
    		int num = 0, S = 0;
    		for(int j = 0; j < n2; ++j)
    			if((i >> j) & 1) ++num, S ^= a[j + n1 + 1];
    		 if(mp.count(S) && mp[S].num + num > Ans.num)	
    		 /*将mp.count(S)改成mp[S].num !=0就不行,
    		 但是选中的字符串的个数是0,还被访问过的状态只有0啊,应该不会有影响啊*/ 
    		 	Ans.num = mp[S].num + num, Ans.S = ((i << n1) | mp[S].S);
    	}
    	write(Ans.num), enter;
    	for(int i = 0; i < n; ++i)
    		if((Ans.S >> i) & 1) write(i + 1), space;
    	enter; 
    	return 0;
    }
    
  • 相关阅读:
    力扣516题、72题、1312题(最长回文子序列,编辑距离,构造回文串)
    力扣53题、1143题(最大子数组问题、最长公共子序列)
    力扣704题、34题(二分查找)
    力扣300题、354题(最长递增子序列,信封嵌套)
    力扣509题、70题(斐波那契数列、爬楼梯)
    力扣206题、92题、25题(反转链表)
    力扣234题(回文链表)
    力扣239题(单调队列)
    力扣496题、503题(单调栈)
    面试题简答题
  • 原文地址:https://www.cnblogs.com/mrclr/p/14618196.html
Copyright © 2011-2022 走看看