Step1 Problem:
有n堆石子,每堆石子数量对应为a[i]。A和B两个人玩Nim游戏,A先手,B可以选择删除不多于m堆石子,使得B获胜的方案数 取模 1e9+7。
数据范围:
正整数 n<=1e3, d <= 10, a[i] <= 1e3.
例子:
Input:
2
5 2
1 1 2 3 4
6 3
1 2 4 7 1 2
Output:
2
5
Step2 Ideas:
Nim游戏: 每堆石子数量 异或和 为0,则先手必输,否则先手必胜。
假设 res = 每堆石子数量异或和;
删除石子堆异或 = res,那么就算是一种方案。
也就是求取不多于m个数异或组成数res的方案数。
01背包
状态dp[j][k]:取 j 个数组成 k 的方案数。
对于第 i 个数 状态转移方程:
dp[j][k] = dp[j][k] + dp[j-1][k^a[i]];
Step3 Code:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1024;
const int MOD = 1e9+7;
int a[N];
ll dp[15][N*2];
int main()
{
int T, n, d;
scanf("%d", &T);
while(T--)
{
scanf("%d %d", &n, &d);
int sum = 0, Max = 0;
for(int i = 0; i < n; i++)
{
scanf("%d", &a[i]);
Max = max(Max, a[i]);
sum ^= a[i];
}
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
for(int i = 0; i < n; i++)
{
for(int j = min(d, n); j >= 1; j--)
{
for(int k = 0; k <= Max*2; k++)
dp[j][k] = (dp[j][k] + dp[j-1][k^a[i]])%MOD;
}
}
ll ans = 0;
for(int i = 0; i <= min(d, n); i++)
ans += dp[i][sum], ans %= MOD;
printf("%lld\n", ans);
}
return 0;
}