Description
Alice and Bob are playing a game. At the beginning, the judge takes out a stone pile of W stones and a black box containing N cards. Every card has a number Ai on it. Alice and Bob takes turns to draw a card from the box. Of course, they will not know the number until they draw the card out of the box. The player then takes away Ai stones from the pile if it is possible. If there are not enough stones, the player draws a card again. The winner is the player who takes away the last stone. Once the box gets empty, they brings back all cards and stones and play the game again until there is a winner.
Now your best friend Alice begs you, the judge, to help her cheat in the game. You have already known the number of cards in the box and their numbers. Given a integer M, You want to know how many values, less or equal to M, W can take so that you can make sure Alice will be the winner of the game.
Input
There are several test cases.
The first line of each test case contains two integers N (1 ≤ N ≤ 10000) and M (1 ≤ M ≤ 100000).
The second line contains N integers Ai (1 ≤ Ai ≤ M). The input ends with two zeros
Output
For each test case output how many values you can choose for W so that Alice will be the winner without fail.
Sample Input
3 8 1 5 7 0 0
Sample Output
3
Hint
站在先手的角度:
如果石头数可以被偶数张卡片组和而成,则有输的可能
如果石头数可以被奇数张卡片组和而成,则有赢的可能
必胜:石头数只由奇数张卡片组和而成
必败:石头数只由偶数张卡片组合而成
平局:任意卡片组合都无法得到石头数
裁判想让先手必胜只需选择根据卡片的组合先手必胜的石头数
dp[i][1] = true表示石头数为i的情况可以由奇数张卡片组成
dp[i][0] = true表示石头数为i的情况可以由偶数张卡片组成
最后计算所有只由奇数张卡片组成的石头数即可
其实用到了滚动数组,有一个“在前i张卡片中”这一维是被省略的
所以直接在输入时dp[a[i]][1]=1是错的,这样做破坏了隐藏的那一个“在前i张卡片中”的那一维
结合滚动数组的01背包写法仔细想想就明白了
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<vector>
#include<algorithm>
#define mem(a,x) memset(a,x,sizeof(a))
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int M = 100004;
const int N = 10004;
int a[N];
int dp[M][2];
int main(){
int n,m;
while (scanf("%d %d",&n,&m),(n||m)){
mem(dp,0);
for (int i = 0;i < n;++i){
scanf("%d",a+i);
// if (a[i]<=m)dp[a[i]][1] = true;
}
for (int i = 0;i < n;++i){
for (int j = m;j > a[i];--j){
if (dp[j-a[i]][0]) dp[j][1] = true;
if (dp[j-a[i]][1]) dp[j][0] = true;
}
dp[a[i]][1] = true;
}
int ans = 0;
for (int i = 1;i <= m;++i){
if (dp[i][1]&&!dp[i][0]){//only odd
++ans;
}
}
printf("%d\n",ans);
}
return 0;
}