Problem - C - Codeforceshttps://codeforces.com/gym/103401/problem/C题目大意为每人每轮最多拿m张牌,谁先取完n张牌谁胜;后手有k张魔法牌,每张魔法牌上写有数字(这里把数字放在c数组里)可以将修改上限变为牌上的数字,发动魔法牌时不能取牌。
拿牌(取石子游戏)有一个必胜策略是将n张牌的剩余个数拿到(m+1)的倍数
(先手不能发动魔法牌,所以只是个无情的拿(m+1)的倍数的机器人)
例如:10张牌,每人最多拿3张,这样的话先手必胜,下面的过程着重看先手拿剩几张牌
先手拿1张,剩余9张,后手拿3张,剩余6张;
先手拿2张,剩余4张,后手拿1张,剩余3张;
先手拿3张,剩余0张,先手获胜;
先手的赢面很大,除了n=(m+1)的倍数,后手必胜的情况。
回到这道题,
显然,当m>=n时,先手必胜;
当n=(m+1)的倍数,后手必胜的情况时,先手不能发动魔法牌,所以不能扭转局面,于是先手必败;
当n!=(m+1)时,先手拿牌拿到n=n-n%(m-1),这时后手有两种情况获胜。
第一种是魔法牌中有(m+1)的倍数刚好是(c[i]+1)的倍数,后手发动牌技能(同时n>c[i]),这样就后手必胜了,也就是说判断条件为只要n大于(c[i]+1)和(m+1)的最小公倍数,那么无论先手怎么取,后手都能控制到(c[i]+1)的倍数;
if(n>(c[i]+1)*(m+1)/__gcd(c[i]+1,m+1)){
cout<<"zyw";
}
第二种是魔法牌的组合,魔法牌中有(c[i]+1)的倍数刚好是(c[j]+1)的倍数,后手先发动c[i](n>c[i]),之后n=n-n%(c[i]+1),这时n是c[i]+1的倍数,然后后手发动c[j](n>c[j]),如果这时n也是c[j]+1的倍数,那么后手就获胜。
if((c[i]+1)*(c[j]+1)/__gcd(c[i]+1,c[j]+1)<=(n-min(n%(c[i]+1),n%(c[j]+1)))){
cout<<"zyw";
}
如果这些情况都没有,那么先手必胜。
贴一个参照了cf上的解法的代码
#include <bits/stdc++.h>
using namespace std;
int main()
{
int c[1010];
int n,m,k;
cin>>n>>m>>k;
for (int i=0;i<k;i++)cin>>c[i];
if (n%(m+1)==0){//because lyw couldn't use card
cout << "zyw";
return 0;
}
if (n<=m){//first win
cout << "lyw";
return 0;
}//until m+1 mod eg.24 12 1 1 ---second win-
n-=n%(m+1);//so when m+1 ,and (m+1)mod c[i]==0 second will win
for (int i=0;i<k;i++){
if (c[i]<=n&&n%(c[i]+1)==0){
cout<<"zyw";
return 0;
}
}
for (int i=0;i<k;i++){
for (int j=i+1;j<k;j++){
long long x =(long long)(c[i]+1)*(c[j]+1)/__gcd(c[i]+1,c[j]+1);//最大公约数
if(x<=(long long)n-min(n%(c[i]+1),n%(c[j]+1))){
cout<<"zyw";
return 0;
}
}
}
cout<<"lyw";
return 0;
}