POJ 3688 Cheat in the Game(作弊博弈)

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 MW 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

We say that Alice is surely to win if and only if the possibility that Alice wins is greater than zero and the possibility that Bob wins is zero. For the sample,  W = 1, 5, 7.

poj.org/problem?id=3688

站在先手的角度:

如果石头数可以被偶数张卡片组和而成,则有输的可能

如果石头数可以被奇数张卡片组和而成,则有赢的可能

必胜:石头数只由奇数张卡片组和而成

必败:石头数只由偶数张卡片组合而成

平局:任意卡片组合都无法得到石头数

裁判想让先手必胜只需选择根据卡片的组合先手必胜的石头数

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



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值