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;
}

上一篇:Codeforces Round #721 (Div. 2)


下一篇:字典--定义