n跟火柴,m+1中取法(第一中取法一定是1),两个人依次来取,取最后一根火柴的人输,但看描述的话好像就是裸的dp,i必败的情况下dp[i+step[j]]必胜,O(n*m)可出,但是这题的n是1e9,m<=8,并且每次取得数量小于等于9,这么小的方案书和方法,这么大的总数势必会出现循环,我们甚至不用去算他的循环节是多少,先根据方案算出一张表,从大到小开始找到第一个可能的循环节就可以结束,一开始循环节最大值我设的100结果挂掉了,写成400才过掉...
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn=2100;
bool dp[maxn];
int n,m,p,q;
int test;
int step[12];
bool check(int r)
{
int i=1;
int j=1+r;
for (int k=0; k<r; k++)
if (dp[i+k]!=dp[j+k]) return false;
return true;
}
int main()
{
// freopen("in.txt","r",stdin);
scanf("%d",&test);
while (test--)
{
memset(dp,false,sizeof dp);
scanf("%d%d",&n,&m);
step[0]=1;
for (int i=1; i<=m; i++)
scanf("%d",&step[i]);
for (int i=1; i<=800; i++)
if (!dp[i])
for (int j=0; j<=m; j++)
dp[i+step[j]]=true;
int rep=400;
while (true)
{
if (check(rep)) break;
rep--;
}
bool ans=dp[n % rep];
if (!ans) puts("SECOND PLAYER MUST WIN ");
else puts("FIRST PLAYER MUST WIN");
// for (int i=1; i<=n; i++)
// cout<<i<<" "<<dp[i]<<endl;
}
return 0;
}