经典博弈论问题,先手必胜还是先手必败,除此之外,外有一个问题即必胜方会尽量快地取胜,必败方会尽可能拖延步数
所以我们可以采取两个数组分别记录自己和对手的状态,状态石子数,存的是取石子的次数
先考虑必胜和必败的两种状态
如果该状态上一状态存在一个必败状态,则该状态必胜,反之必败
所以问题就简单了对于自己而言,如果该状态必胜,则取石子的个数是上一状态(可以理解为对手必胜状态)的取个最小,然后+1即可
f[i]=min(f[i],dp[i-prime[j]]+1);
如果该状态必败,则等于是对手必胜状态,那么,上一状态即是自己的必胜状态,取个最大+1即可
这个时候要维护的是对手的状态
dp[i]=max(dp[i],f[i-prime[j]]+1);
#include <bits/stdc++.h>
#define inf 0x7fffffff
//#define ll long long
#define int long long
//#define double long double
//#define double long long
#define re int
//#define void inline void
#define eps 1e-8
//#define mod 1e9+7
#define ls(p) p<<1
#define rs(p) p<<1|1
#define pi acos(-1.0)
#define pb push_back
#define mk make_pair
#define P pair < int , int >
using namespace std;
const int mod=1e9+7;
//const int inf=1e18;
const int M=1e8;
const int N=4e6+5;//??????.???? 4e8
int prime[N],v[N];
int n,f[N],m,dp[N];
void Prime()
{
for(re i=2;i<=2e4;i++)
{
if(!v[i]) v[i]=i,prime[++m]=i;
for(re j=1;j<=m;j++)
{
if(prime[j]*i>2e4||prime[j]>v[i]) break;
v[i*prime[j]]=prime[j];
}
}
}
void init()
{
Prime();
memset(f,-1,sizeof(f));
for(re i=2;i<=2e4;i++)
{
for(re j=m;j>=1;j--) if(i-prime[j]>=0) if(f[i-prime[j]]==-1)
{
if(f[i]==-1) f[i]=1e18;
f[i]=min(f[i],dp[i-prime[j]]+1);
}
if(f[i]==-1) for(re j=m;j>=1;j--) if(i-prime[j]>=0) if(f[i-prime[j]]!=-1) dp[i]=max(dp[i],f[i-prime[j]]+1);
}
}
void solve()
{
int n;
cin>>n;
cout<<f[n]<<endl;
}
signed main()
{
init();
int T=1;
cin>>T;
for(int index=1;index<=T;index++)
{
solve();
// puts("");
}
return 0;
}
/*
*/