P1857 质数取石子(博弈论dp1)

P1857 质数取石子

经典博弈论问题,先手必胜还是先手必败,除此之外,外有一个问题即必胜方会尽量快地取胜,必败方会尽可能拖延步数

所以我们可以采取两个数组分别记录自己和对手的状态,状态石子数,存的是取石子的次数

先考虑必胜和必败的两种状态

如果该状态上一状态存在一个必败状态,则该状态必胜,反之必败

所以问题就简单了对于自己而言,如果该状态必胜,则取石子的个数是上一状态(可以理解为对手必胜状态)的取个最小,然后+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;
}
/*



*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值