NOJ-1086-花生米(五)

159 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第22天,点击查看活动详情

花生米(五)

描述

五一长假第六天,Tom在QQ上遇到了Kitty。呵呵,Kitty,在离散数学课上认识的PPMM……等等!Tom恍然大悟:自己这一生除了看帖不回之外最大的错误就是离散数学没学好! 五一长假第七天,Tom和Jerry在仓库散步的时候发现了一堆花生米(仓库,呵呵,仓库…)。这次Tom制定分花生米规则如下: 1、首先选出最苦的一粒花生米,放到一个瓶子里; 2、把剩下的花生米做成花生酱,Tom和Jerry轮流取一些花生酱吃掉; 3、第一个取的人只能取1.0克,以后取花生酱的数量不能少于两个人已经取过的总数量且不能超过两个人已经取过的总数量的三倍; 4、不能按规则3取花生酱的人必须吃掉瓶子里的花生米; 5、为显示规则的公平性,Jerry可以选择先取或者后取。 Jerry当然希望瓶子里的花生米被Tom吃掉。请计算,Jerry为了达到目的应该先取还是后取。

输入

本题有多个测例,每个测例的输入是一个浮点数w,w大于1.0小于等于1000.0,w最多只有一位小数,代表花生酱的数量,单位为克。 w小于0表示输入结束,不需要处理。

输出

每个测例在单独的一行内输出一个整数:Jerry先取输出1;Tom先取输出0。

输入样例

1.5 7.9 -1

输出样例

1 0

思路

这个题和花生米(三) 极其相似,只是 花生米(三) 中要求是后者取的花生数不能超过前者的两倍,而这个题后者取的花生数w>=前面取的花生的总数并且w<=前面取的花生的总数的三倍,并且Jerry希望Tom无法按则规则取花生这样Jerry就胜利了。显然这个题和 花生米(三) 都无法确认当前人取花生的数量,只能确认一个范围进行枚举。并且这个题还是小数。由于最多一位小数,那就全部乘10,这样就全部转化成整数问题了。dp[res]表示剩余res个的时候后手的必胜或者必败,dp[res]=0表示剩余res个的情况后手必胜。从 花生米(三) 知道一个状态要是必胜态,必须保证推导它的之前的状态都是必败(即要后手必胜,必须保证先手必败),设先手取了c个花生米,那么对于后手就要枚举他选择i个花生的所有状态(i from c to 3 * c),并且dfs的结果均为1(即先手必败)。这里用到了记忆化搜索,不赘述。这个题可以用一维数组表示的原因是由c我们就可以得到res,由res就可以得到c,因为res+c=n,所以二维数组就可以简化成一维。而 花生米(三) 则不能这样表示。

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=10000+50;
int dp[maxn];
int dfs(int res,int c){
    int i;
    if(res<c){
        dp[res]=0;
        return dp[res];
    }
    if(dp[res]!=-1)return dp[res];
    int sign=1;
    for(i=c;i<=3*c;i++){
        if(res<i)break;
        sign&=dfs(res-i,c+i);
        if(sign==0)break;
    }
    dp[res]=0;
    if(!sign)dp[res]=1;
    return dp[res];
}
int main(){
    int tot=0;
    while(1){
        int i;
        double x;
        cin>>x;
        if(x<0)break;
        for(i=0;i<=x*10;i++){
            dp[i]=-1;
        }
        int w=x*10;
        cout<<1-dfs(w-10,10)<<endl;
    }
    return 0;
}