solution
我们知道,一个局面当且仅当每堆石子数量的异或和为(0)时后手必胜。那么我们如果给(Alice)指定第一次选的堆,那么当他选完一次之后就成了后手。所以他肯定会尽量的使剩下的石子数量异或和为(0)。
现在假设我们强制他选第(i)堆,且第(i)堆有(x)个石子。那么他可以通过选一次使得这堆石子的数量位于([0,x-1])。所以我们其他石子数量的异或和不能位于([0,x-1])这个区间。那么用(f[i][j])表示前(i)堆石子异或和为(j)的方案数。(g[i][j])表示([i,n])堆石子,异或和为(j)的方案数。然后枚举一下强制选的位置。合并这两个(dp)数组就行了。
code
/*
* @Author: wxyww
* @Date: 2020-04-28 07:27:43
* @Last Modified time: 2020-04-28 07:35:08
*/
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<ctime>
#include<cmath>
using namespace std;
typedef long long ll;
const int N = 310,mod = 1e9 + 7;
ll read() {
ll x = 0,f = 1;char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1; c = getchar();
}
while(c >= '0' && c <= '9') {
x = x * 10 + c - '0'; c = getchar();
}
return x * f;
}
int f[N][N],g[N][N],a[N];
int main() {
int n = read();
for(int i = 1;i <= n;++i) a[i] = read();
f[0][0] = 1;g[n + 1][0] = 1;
for(int i = 1;i <= n;++i) {
for(int j = 0;j < (1 << 8);++j) {
f[i][j] += (f[i - 1][j ^ a[i]] + f[i - 1][j]) % mod;
f[i][j] >= mod ? f[i][j] -= mod : 0;
}
}
for(int i = n;i >= 1;--i) {
for(int j = 0;j < (1 << 8);++j) {
g[i][j] += (g[i + 1][j ^ a[i]] + g[i + 1][j]) % mod;
g[i][j] >= mod ? g[i][j] -= mod : 0;
}
}
ll ans = 0;
for(int i = 1;i <= n;++i) {
for(int j = a[i];j < (1 << 8);++j) {
for(int k = 0;k < (1 << 8);++k) {
ans += 1ll * f[i - 1][k] * g[i + 1][j ^ k] % mod;
ans >= mod ? ans -= mod : 0;
}
}
}
cout<<ans;
return 0;
}