【问题描述】

DD 和 MM 正在玩取石子游戏。他们的游戏规则是这样的:桌上有若干石子,DD 先取,轮流取,每次必须取质数个。如果某一时刻某一方无法从桌上的石子中取质数个,比如说剩下 0 个或 1 个石子,那么他/她就输了。
DD 和 MM 都很聪明,不管哪方存在一个可以必胜的最优策略,他/她都会按照最优策略保证胜利。于是,DD 想知道,对于给定的桌面上的石子数,他究竟能不能取得胜利呢?

当 DD 确定会取得胜利时,他会说:“不管 MM 选择怎样的取石子策略,我都能保证至多 X 步以后就能取得胜利。”那么,最小的满足要求的 X 是多少呢?注意,不管是 DD 取一次石子还是 MM 取一次石子都应该被计算为“一步”。

【输入格式】

第一行有一个整数 N,表示这个输入文件中包含 N 个测试数据。
第二行开始,每行有一个测试数据,其中仅包含一个整数,表示桌面上的石子数。

【输出格式】

你需要对于每个输入文件中的 N 个测试数据输出相应的 N 行。
如果对于该种情形是 DD 一定取得胜利,那么输出最小的 X。否则该行输出 -1。

【样例输入】

3
8
9
16

【样例输出】

1
-1
3

【样例说明】

当桌上有 8 个石子时,先取的 DD 只需要取走 7 个石子剩下 1 个就可以在一步之后保证胜利,输出 1。
当桌上有 9 个石子时。若 DD 取走 2 个,MM 会取走 7 个,剩下 0 个,DD 输。若 DD 取走 3 个,MM 会取走 5 个,剩下 1 个,DD 输。DD 取走 5 个或者 7 个的情况同理可知。所以当桌上有 9 个石子时,不管 DD 怎么取,MM 都可以让 DD 输,输出 -1。

当桌上有 16 个石子时,DD 可以保证在 3 步以内取得胜利。可以证明,为了在 3 步内取得胜利,DD 第一步必须取 7 个石子。剩下 9 个石子之后,不管第二步 MM 怎么取,DD 取了第三步以后可以保证胜利,所以输出 3。

【数据范围】

输入文件中的数据数 N<=10。
每次桌上初始的石子数都不超过 20000。

【分析】

动态规划。

首先打出素数表,用v[i]来保存DD有i颗石子的时候是否可以胜利,1代表可以,0代表不可以。

v[i]通过前面的状态可以计算出来,如果v[i-p](p为素数)为false,显然v[i]就应该为1,因为多取了一次。

然后对于不同的v[i]状态分情况讨论,

f[i]=min{f[i-prime[j]]}(v[i]=1)计算可能获胜时最少的步数

f[i]=max{f[i-prime[j]]}(v[i]=0)计算不可能获胜时最多的步数

#include <cstdlib>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <queue>
#define LOCAL
const int maxn=+;
using namespace std;
int prime[maxn];
int flag[maxn],f[maxn];
int v[maxn]; void prepare(); int main(){
int T,n;
#ifdef LOCAL
freopen("data.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
prepare();//打表
scanf("%d",&T);
while (T--){
scanf("%d",&n);
if (v[n]) printf("%d\n",f[n]);
else printf("-1\n");
}
return ;
}
void prepare(){
prime[]=;
for (int i=;i<=;i++){
int g=;
for (int j=;j<=prime[];j++){
if (i%prime[j]==){
g=;
break;
}
}
//增加新的质数
if (g) prime[++prime[]]=i;
flag[i]=prime[];
}
memset(v,,sizeof(v));
memset(f,,sizeof(f));
for (int i=;i<=;i++){
for (int j=flag[i];j>=;j--)
if (!v[i-prime[j]]){
v[i]=;
break;
}
//printf("%d\n",v[i]);
}
int tmp=;
for (int i=;i<=;i++){
if (v[i]){
tmp=;
for (int j=flag[i];j>=;j--)
if (!v[i-prime[j]]) tmp=min(tmp,f[i-prime[j]]);
}
else {
tmp=-;
for (int j=flag[i];j>=;j--)
tmp=max(tmp,f[i-prime[j]]);
}
f[i]=tmp+;
}
return;
}

【COGS 56】质数取石子的更多相关文章

  1. Cogs 56. 质数取石子(博弈)

    质数取石子 ★★ 输入文件:stonegame.in 输出文件:stonegame.out 简单对比 时间限制:1 s 内存限制:128 MB 问题描述 DD 和 MM 正在玩取石子游戏.他们的游戏规 ...

  2. P1857 质数取石子 (DP,递推)

    题目描述 桌上有若干个石子,每次可以取质数个.谁先取不了,谁就输.问最少几步能赢?(一个人取一次算一步) 输入输出格式 输入格式: 第一行N,表示有N组数据 接下来N行为石子数 输出格式: 每组数据一 ...

  3. 洛谷 P4018 Roy&October之取石子

    洛谷 P4018 Roy&October之取石子 题目背景 Roy和October两人在玩一个取石子的游戏. 题目描述 游戏规则是这样的:共有n个石子,两人每次都只能取 p^kpk 个(p为质 ...

  4. 洛谷 P4706 取石子 解题报告

    P4706 取石子 题目描述 现在 Yopilla 和 yww 要开始玩游戏! 他们在一条直线上标记了 \(n\) 个点,从左往右依次标号为 \(1, 2, ..., n\) .然后在每个点上放置一些 ...

  5. 洛谷 Roy&October之取石子

    题目背景 Roy和October两人在玩一个取石子的游戏. 题目描述 游戏规则是这样的:共有n个石子,两人每次都只能取pk 个(p为质数,k为自然数,且pk小于等于当前剩余石子数),谁取走最后一个石子 ...

  6. 洛谷——P4018 Roy&October之取石子

    P4018 Roy&October之取石子 题目背景 Roy和October两人在玩一个取石子的游戏. 题目描述 游戏规则是这样的:共有n个石子,两人每次都只能取p^kpk个(p为质数,k为自 ...

  7. P4018 Roy&October之取石子

    题目背景 Roy和October两人在玩一个取石子的游戏. 题目描述 游戏规则是这样的:共有n个石子,两人每次都只能取 p^kpk 个(p为质数,k为自然数,且 p^kpk 小于等于当前剩余石子数), ...

  8. 洛谷P4018 Roy&October之取石子

    题目背景 \(Roy\)和\(October\)两人在玩一个取石子的游戏. 题目描述 游戏规则是这样的:共有\(n\)个石子,两人每次都只能取\(p^k\)个(\(p\)为质数,\(k\)为自然数,且 ...

  9. {HDU}{2516}{取石子游戏}{斐波那契博弈}

    题意:给定一堆石子,每个人最多取前一个人取石子数的2被,最少取一个,最后取石子的为赢家,求赢家. 思路:斐波那契博弈,这个题的证明过程太精彩了! 一个重要的定理:任何正整数都可以表示为若干个不连续的斐 ...

随机推荐

  1. 线性链表的双向链表——java实现

    .线性表链式存储结构:将采用一组地址的任意的存储单元存放线性表中的数据元素. 链表又可分为: 单链表:每个节点只保留一个引用,该引用指向当前节点的下一个节点,没有引用指向头结点,尾节点的next引用为 ...

  2. bzoj2427

    一开始读错题导致各种不会做,无奈其实是一道水题,缩点反向建图树形dp即可 type link=^point; point=record po:longint; next:link; end; ..] ...

  3. Light OJ 1004 - Monkey Banana Problem(DP)

    题目大意: 给你一菱形的数字阵,问从最上面走到最下面所能获得的最大值是多少? #include<cstdio> #include<cstring> #include<io ...

  4. Fire Net HDU 1045

    简单深搜,可以完全暴力,不会超时的. #include<iostream> #include<cstring> #include<cmath> using name ...

  5. 【转】如何开发苹果iOS操作平台下的应用程序?

    原文网址:http://zhidao.baidu.com/link?url=vxRWjCchSstFmVKvxEqLqfqomu2h5kF-NLAIVEehQgN_FnYtEi4f5yPMS6ywbU ...

  6. bzoj1227 [SDOI2009]虔诚的墓主人(组合公式+离散化+线段树)

    1227: [SDOI2009]虔诚的墓主人 Time Limit: 5 Sec  Memory Limit: 259 MBSubmit: 803  Solved: 372[Submit][Statu ...

  7. openresty安装lua和nginx相关

    server{ listen ; server_name a.com; index index.php; root /usr/share/nginx/html; location / { if (!- ...

  8. [PWA] 13. New db and object store

    Create a db: import idb from 'idb'; var dbPromise = idb.open('test-db', 2, function (upgradeDb) { sw ...

  9. 1小时学Python脚本

    如果我们有这么一项任务:简单測试局域网中的电脑是否连通.这些电脑的ip范围从192.168.0.101到192.168.0.200.        思路:用shell编程.(Linux一般是bash而 ...

  10. [转] Java中ArrayList类的用法

    1.什么是ArrayList ArrayList就是传说中的动态数组,用MSDN中的说法,就是Array的复杂版本,它提供了如下一些好处: 动态的增加和减少元素 实现了ICollection和ILis ...