甲乙两人面对若干堆石子,其中每一堆石子的数目可以任意确定。
两人轮流按下列规则取走一些石子,游戏的规则如下:
1.每一步应取走至少一枚石子;
2.每一步只能从某一堆中取走部分或全部石子;
3.如果谁无法按规则取子,谁就是输家。
如果甲乙两人都采取最优的策略,甲先拿,请问,是甲必胜还是乙必胜.
输入格式:
多组数据,每组数据两行,第一行是一个整数N, 2<=N<=10000
下一行是N个正整数,代表每堆的石子数,石子数在32位整数内。
输出格式:
每组测试数据输出一行,如果甲存在必胜策略,输出"Win",否则输出"Lost"
- #include <iostream>
- using namespace std;
- int main()
- {
- int n=0;
- while(cin>>n){
- int i=n;
- int sum=0;
- int num=0;
- while(i--)
- {
- cin>>num;
- sum ^= num;
- }
- if(sum!=0){
- cout<<"Win\n";
- }else{
- cout<<"Lost\n";
- }
- }
- return 0;
- }
Solution:
对于游戏A来说,任意的一个初始局面S=(a1,a2, …, an),我们把这里的ai都看成是二进制数。令#S=a1 a2 … an。若#S≠0,则先行者(甲)有必胜策略;否则#S=0,这时后行者(乙)有必胜策略。
可同时从多堆石子里取石子的取石子问题:
N堆石子,每堆有Xi个,轮流取,每次从最多K堆石子里取石子(在不同堆里取的数目可以不同)。最普通的取石子问题就是K=1的情况。
今天codeforces的第四题,想不出,赛后可耻地看了别人代码。
方法就是把每堆石子的数目转成2进制,只要某一位上为1的数目个数不是(K+1)的整数倍,就先手赢。
所以先手的策略就是把每一位上的数字和都搞成K+1的倍数。
怎么搞呢:找到最高的和不是K+1倍数的那一位,假设是有N个1,挑N%(K+1)个数字,把这一位的1变成0,那么这些数字的剩下几位就可以任自己决定了。
然后往低位一位位移过去,如果某一位上就算怎么改都到不了K+1的倍数,就挑几个当前位为1的数字进来,把1变成0,那可控数字就增加了,最多可以增加到K个,那K个可控数字就肯定可以把剩下的任意一位上的和搞成K+1倍数。
从一堆石子里取:
两人取一堆n个石子 先手不能全部取完 之后每人取的个数不能超过另一个人上轮取的数*K
给n,K判断先手必胜并求要必胜时第一步取多少石子
ll a[3000000],b[3000000];
int main(){
int i,j,t,k;
ll n,ans;
scanf("%d",&t);
while(t--){
scanf("%d%lld",&k,&n);
i=j=0;
a[0]=b[0]=1;
while(a[i]<n){
i++;
a[i]=b[i-1]+1;
while(a[j+1]*k<a[i]) j++;
if(a[j]*k<a[i]) b[i]=b[j]+a[i];
else b[i]=a[i];}
if(a[i]==n) ans=(ll)n-i-1;
else ans=(ll)n-i;
printf("%lld\n",ans);}
return 0;}<span style="font-family:Arial;color:#333333;"><span style="font-size: 14px; line-height: 26px;">
</span></span>