P5675
动态规划+博弈论
要让\(Alice\)必败有两种方式
第一种,给出的若干堆先手必败,也就是异或和为0的时候必败。
第二种,把第一堆单独拿出来,然后看一下这一堆和其余的关系,假设这一堆有\(a_i\)个,其余的异或和为\(k\),如果\(Alice\)可以通过移动\(a_i\)将后续状态变为先手必败态,那么这一堆就是不合法的。不难发现只要\(a_i>k\),\(Alice\)就可以完成这样的行动。
对于这样的问题可以考虑枚举\(a_i\),找到对所有的\(k\)满足的方案数,而\(k\)最大也不会超过\(255\),所以考虑\(dp\)。
\(dp[i][j]\)表示前\(i\)个数异或和为\(j\)的方案数。
转移为,\(dp[i][j] = dp[i-1][j-1]+dp[i-1][j\oplus a[i]]\)。
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
using namespace std;
#define ll long long
const ll N = 500;
const ll mod = 1e9+7;
ll a[N],dp[N][300];//dp[i][j]表示前i个点异或和为j的值
int main() {
ios::sync_with_stdio(false);
ll n;cin>>n;
for(ll i = 1;i <= n;i++)cin>>a[i];
ll ans = 0;
dp[0][0] = 1;
for(ll k = 1;k <= n;k++){
for(ll i = 1;i <= n;i++){
for(ll j = 0;j < 256;j++) {
if (i == k) dp[i][j] = dp[i-1][j];
else dp[i][j] = (dp[i-1][j]+dp[i-1][j^a[i]])%mod;
}
}
for(ll i = a[k];i < 256;i++){
ans = (ans+dp[n][i]%mod)%mod;
}
}
cout<<ans<<endl;
return 0;
}