设FA为A的牌中数字异或和,FB为B的。
则有性质:
ans = (所有的(A&B=0)个数 + (FA=FB且A&B=0)的个数)/2。即所有的FA>FB的个数(除2是因为这里FA>FB的个数等于FA<FB的个数)加上FA=FB(A&B=0)的个数(除2是因为会算两次),这些情况都算A赢。(FA=FB即有FA^FB = 0)可以定义状态dp[i][s]为考虑前i个数,当前FA^FB=s的(A,B)个数。我这里是直接算的。
代码:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; #define N 2007 int a[18]; int main() { int i,j,k,n,m,A; scanf("%d",&n); for(i=0;i<n;i++) scanf("%d",&a[i]); int S = (int)pow(3,n); //所有A&B=0的(A,B)个数 int AA = (1<<n) - 1; int cnt = 1; //A,B都不取 int resA; for(A=1;A<=AA;A++) { j = A; k = m = resA = 0; while(j) { if(j%2) { resA ^= a[k]; m++; } k++; j/=2; } if(resA == 0) //则可取A,B为resA的子集使FA^FB=resA=0,子集数为2^m(m为取得数的个数) cnt += 1<<m; } int res = (S+cnt)/2; printf("%d\n",res); return 0; }