题意:俩个人,总共有n个球,每个人每次只能拿a[i]个球,每个人分别有m 个a[i],题目保证a[i]单调递增,当谁不能拿球的时候他就输了。
题目:https://vjudge.net/contest/413430#problem/G
题解: 一位大佬朋友写的代码,本菜鸡只是理解后翻译了一下。
这里的dpl和dpm的值只有0和1,代表桌子上剩余i个球的时候,这个时候谁去拿,他是会输还是会赢,所以会有dpl[i]=dpm[i]的情况,这个时候谁去拿谁都能保证自己赢,就看谁先手了,因为龙龙是先手,所以这种情况龙龙一定会赢。else if(dpm[i-lo[j]]==0)
这里进行判断的时候,i-lo[j]是一定比i小的,这个时候毛毛是赢还是输的状态是已经被判断过的,所以这么一直递推下去,就会有结果。
#include <iostream> #include<bits/stdc++.h> using namespace std; int lo[120];//表示longlong每次能够拿的球 int ma[120];//表示maomao每次能够拿的球 int dpl[5100];//只有1和0俩个值,剩余i个球的时候,这个时候龙龙去拿是输还是赢 int dpm[5100];//只有1和0俩个值,剩余i个球的时候,这个时候毛毛去拿是输还是赢 int main() { int n,m; cin>>n>>m; for(int i=1; i<=m; i++) { cin>>lo[i]; } for(int i=1; i<=m; i++) { cin>>ma[i]; } for(int i=1; i<=n; i++) //从1到n分别枚举剩i个球的时候这个时候谁去拿谁是输还是赢, { int flag=0; //为0的时候代表这个时候谁去拿谁输 for(int j=1; j<=m; j++)//遍历龙龙能够拿的数量 { if(lo[j]>i)//当它拿的数量大于剩余的球的时候break { break; } //剩余i个球,这个时候龙龙如果拿走lo[j]个后,剩余的球毛毛去拿会不会输, else if(dpm[i-lo[j]]==0)//如果会的话,那么就跳出,i这个时候龙龙去拿,龙龙就赢 { //这个时候可能毛毛去拿,毛毛赢,那么遍历龙龙可以去拿的每一种情况,如果每一种情况,毛毛都可以赢 flag=1;//那么剩余i的时候龙龙去拿,龙龙就输了,如果存在一个毛毛输的情况,那么龙龙就走这种情况,龙龙就赢 break; } } if(flag==1)dpl[i]=1;//如果龙龙可以赢,就标记龙龙赢 flag=0; for(int j=1; j<=m; j++) //这里和上面龙龙的情况一样,只不过是换了个人 { if(ma[j]>i) { break; }//遍历毛毛拿走ma[j]个球后,龙龙是否输,如果有一种情况是龙龙输了,那么在剩余i个球的时候 else if(dpl[i-ma[j]]==0)//毛毛去拿,毛毛就可以赢,否则毛毛就输 { flag=1; break; } } if(flag==1)dpm[i]=1; } //因为龙龙是先手,看一下桌子上剩余n个球的时候,龙龙去拿是输还是赢 if(dpl[n])printf("Long Long nb!\n"); else printf("Mao Mao nb!\n"); return 0; }
Nim plus Gym - 102878G(博弈题,dp做法(类似背包))
原文:https://www.cnblogs.com/Are-you-ready/p/14170187.html