1堆石子有n个,两人轮流取.先取者第1次可以取任意多个,但不能全部取完.以后每次取的石子数不能超过上次取子数的2倍。取完者胜.先取者负输出"Second win".先取者胜输出"First win".
取石子游戏
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3807 Accepted Submission(s): 2272
Problem Description
1堆石子有n个,两人轮流取.先取者第1次可以取任意多个,但不能全部取完.以后每次取的石子数不能超过上次取子数的2倍。取完者胜.先取者负输出"Second win".先取者胜输出"First win".
Input
输入有多组.每组第1行是2<=n<2^31. n=0退出.
Output
先取者负输出"Second win". 先取者胜输出"First win".
参看Sample Output.
参看Sample Output.
Sample Input
2 13 10000 0
Sample Output
Second win Second win First win
Source
首先试图找规律,我竟然用纸笔找规律,弄了半天发现完全不行,情况实在太复杂,开始用DP机器打表,
立马找到规律。
找规律代码:其中DP(limit,x)表示现在剩下x个,根据上一次取的数量确定这次最多取limit个。
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
int dp[1020][1020];
bool DP(int limit,int x)
{
limit=min(limit,x);
if(~dp[limit][x]) return dp[limit][x];
dp[limit][x]=0;
for(int i=1;i<=limit;i++)
{
dp[limit][x]|= !DP( 2*i,x-i);
}
return dp[limit][x];
}
int main()
{
memset(dp,-1,sizeof dp);
for(int i=2;i<=100;i++)
{
if(!DP(i-1,i)) printf("second: %d \n",i);
}
return 0;
}
AC代码:
这个解法一直有一个困惑:为什么G++会提示超内存,而用C++内存使用少得可怜?
/**==========================================
* This is a solution for ACM/ICPC problem
*
* @source: hdu 2516
* @type:
* @author: wust_ysk
* @blog: http://blog.csdn.net/yskyskyer123
* @email: 2530094312@qq.com
*===========================================*/
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<set>
using namespace std;
int n;
set<int >se;
void pre()
{
se.insert(2);
se.insert(3);
int a=2,b=3;
while(a+b>=0)
{
se.insert(a+b);
int t=b;
b=a+b;
a=t;
}
}
int main()
{
pre();
while(~scanf("%d",&n)&&n)
{
puts(se.count(n)?"Second win":"First win");
}
return 0;
}