题意:
给定n个字符串,求最多选几个并保证所有字母出现偶数次
n最大为24,直接枚举2^24,对于18s的实现貌似也是可以接受的,但必然不好。想了很久降复杂度的方法都没想到好的,用中途相遇发只能降到(2^n/2)log(n),对于n很大还是无力
中途相遇法指把原问题化为两个独立的子问题,一半通过枚举暴力完成,另一半枚举时利用map等结构查询前一半的结果,合并得出最终结果
/* author:jxy lang:C/C++ university:China,Xidian University **If you need to reprint,please indicate the source** */ #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <map> using namespace std; int count_one(int x)//分治计数 { x=(x&0x55555555)+(x>>1&0x55555555); x=(x&0x33333333)+(x>>2&0x33333333); x=(x&0x0F0F0F0F)+(x>>4&0x0F0F0F0F); x=(x&0x00FF00FF)+(x>>8&0x00FF00FF); x=(x&0x0000FFFF)+(x>>16&0x0000FFFF); return x; } int org[26],n; map<int,int> table; int main() { while(~scanf("%d",&n)) { char s[50]; int i,j,len; for(i=0;i<n;i++) { scanf("%s",s); len=strlen(s); org[i]=0; for(j=0;j<len;j++) { org[i]^=1<<(s[j]-'A'); } } int n1=n>>1,n2=n-n1,tmp,t,now; tmp=1<<n1;now=0; table.clear(); for(i=0;i<tmp;i++)//枚举一半 { t=i;j=0; now=0; while(t) { if(t&1)now^=org[j]; j++; t>>=1; } if(count_one(table[now])<count_one(i))table[now]=i;//记录最大值 } tmp=1<<n2; int ans=0; for(i=0;i<tmp;i++) { t=i;j=0; now=0; while(t) { if(t&1)now^=org[j+n1]; j++; t>>=1; } if(table[now]!=0&&count_one(ans)<(count_one((i<<n1)^table[now])))//题目没说多组情况,用<可以过 { ans=(i<<n1)^table[now]; } } printf("%d\n",count_one(ans)); for(i=0;ans;i++,ans>>=1) if(ans&1) printf("%d%c",i+1,ans>>1?' ':'\n'); } }