ZOJ 3599 K倍动态减法游戏

下面的文字辅助理解来自http://blog.csdn.net/tbl_123/article/details/24884861

博弈论中的 K倍动态减法游戏,难度较大,参看了好多资料才懵懂!

此题可以看作 Fibonacci 博弈的扩展,建议没弄懂 Fibonacci博弈的先学那个,个人整理 http://blog.csdn.net/tbl_123/article/details/24033245 ;

而说扩展体现在数列不再是Fib数列,是根据 k 的值自行构造的,其它换汤不换药,具体构造方法如下:

这儿方便说明白,首先根据k的值分情况讨论:

1) 当 k = 1 时,必败态为 n = 2 ^ i, 因为我们把数按二进制分解后,拿掉二进制的最后一个1,那么对方必然不能拿走倒数第二位的1,因为他不能拿的比你多。你只要按照这个策略对方一直都不可能拿完。所以你就会赢。而当分解的二进制中只有一个1时,因为第一次先手不能全部取完,所以后手一定有办法取到最后一个1,所以必败!

举个例子,当 n = 6 = (110)时:

第一轮:先手第一次取最右边的1,即2个,此时还剩4(100)个,后手能取1或2个;

第二轮:假如上轮后手取的两个,先手再取两个直接赢了

假如后手取了一个,那么还剩三个,自己只能去1个,以后也只能取一个,所以必胜!

2) 当 k = 2 时,赤裸裸的Fibonacci博弈了,具体这儿不多说,自己再上述博客已写的很明白了。其实n经拆解后也可以表示成二进制的形式,用 k = 1时的方法来理解,比如 n = 11 = 7 + 3 + 1,可表示成 10101;

3) 当 k 取任意非零正值时,重点来了:

犹如Fibonacci博弈,我们首先要求一个数列,将n分解成数列中一些项的和,然后就可以按Fibonacci博弈的解决方法来完成,也可以按二进制的方法来理解,每次取掉最后一个1 还是符合上面的条件。

我们用a数组表示要被求的数列,b数组中的b[i]保存 a[0...i] 组合能够构造的最大数字。这儿有点难理解,所谓构造就是指n分解为Fib数相加的逆过程。举例说明,当k = 2 时,a[N]={1, 2, 3, 5, 8, 13, 21, 33....} (Fibonacci数组);那么b[3] 即 1、2、 3 能够构造的最大数字,答案是4,有点匪夷所思?或许你会问为什么不是5、6或者其它的什么,其实是这样的 ,4 能分解成 1+3 是没有争议的,但5能分解成2+3吗? 不能,因为5本身也是Fibonacci数;6虽然能分解,但不是分解成1+2+3,而是分解成1+5。

经过上述,我们知道b[i] 是 a[0...i] 能够构造出的最大数字,那么a[i +1] = b[i]+1;因为a数组(Fib数组)所存的数字都是不可构造的(取到它本身就是必败态),显然a[0...i]构造的最大数字 + 1 即为下一个不可构造的数字了(a[i + 1])。

然后关于b[i]的计算,既然是a[0...i]构造最大数字,那么 a[i]是一定要选用的(这儿需要一定的推理,a[i]构造数字时,相邻的j个是不能同时用的,就像上述的2、3不能构造出5一样,推理请自己完成),那么要选用的下一项只能递减寻找,直到找到 a[t] 满足 a[t] * K < a[i] ,而b[t]就是a[0...t]所能构造的最大数字,再加上a[i], 即为a[0...i]能构造的最大数字,于是b[i] = b[t] + a[i]。

求的数列后,之后的工作就简单了,跟Fibonacci博弈一样一样的,如果n=数列中的数,则必败,否则必胜;必胜时还要求输出第一步取法,其实就是分解的数列中最小的一个,将见代码。

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
LL a[3000000],b[3000000];
int main()
{
    int T;
    scanf("%d",&T);
    while (T--)
    {
        LL N,M;
        cin >> M >> N;
        a[0] = b[0] = 1;
        int i = 0 ,j = 0;
        while (N > a[i])
        {
            i++;
            a[i] = b[i - 1] + 1;
            while (a[j + 1] * M < a[i]) j++;
            if (a[j] * M < a[i]) b[i] = b[j] + a[i];
            else b[i] = a[i];
        }
        LL ans;
        if (N == a[i]) ans = N - i - 1;
        else ans = N - i;
        cout << ans << endl;
    }
    return 0;
}
时间: 2024-07-31 04:52:31

ZOJ 3599 K倍动态减法游戏的相关文章

uva 1567 - A simple stone game(K倍动态减法游戏)

题目链接:uva 1567 - A simple stone game 题目大意:给定K和N,表示一堆石子有N个,先手第一次可以取1~N-1个石子,取到最后一个石子的人胜利,单词每次操作时,取的石子数不能超过对手上一次取的石子数m的K倍.问先手是否可以必胜,可以输出最小的首次操作. 解题思路:这题想了一天,又是打表找规律,又是推公式的,楞是做不出来,后来在网上找到了一篇题解,将的很清楚,解题宝典 /******************* * K倍动态减法游戏 * 参考:http://www.cn

【题集】k倍区间(抽屉原理)

例1:http://lx.lanqiao.cn/problem.page?gpid=T444 蓝桥杯 问题描述 给定一个长度为N的数列,A1, A2, ... AN,如果其中一段连续的子序列Ai, Ai+1, ... Aj(i <= j)之和是K的倍数,我们就称这个区间[i, j]是K倍区间. 你能求出数列中总共有多少个K倍区间吗? 输入格式 第一行包含两个整数N和K.(1 <= N, K <= 100000) 以下N行每行包含一个整数Ai.(1 <= Ai <= 10000

k倍区间

用前缀和来求区间和,然后用一个二重循环穷举,但是因为问题规模为100000,所以超时(28分) 超时代码: #include <stdio.h> #include <memory.h> #include <math.h> #include <string> #include <string.h> #include <vector> #include <set> #include <stack> #include

第八届蓝桥杯-k倍区间

历届试题 k倍区间 时间限制:2.0s 内存限制:256.0MB 提交此题 问题描述 给定一个长度为N的数列,A1, A2, ... AN,如果其中一段连续的子序列Ai, Ai+1, ... Aj(i <= j)之和是K的倍数,我们就称这个区间[i, j]是K倍区间. 你能求出数列中总共有多少个K倍区间吗? 输入格式 第一行包含两个整数N和K.(1 <= N, K <= 100000) 以下N行每行包含一个整数Ai.(1 <= Ai <= 100000) 输出格式 输出一个整

hihocoder-1796-完美K倍子数组

hihocoder-1796-完美K倍子数组  #1796 : 完美K倍子数组 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 如果一个数组满足长度至少是2,并且其中任意两个不同的元素Ai和Aj (i ≠ j)其和Ai+Aj都是K的倍数,我们就称该数组是 完美K倍数组. 现在给定一个包含N个整数的数组A = [A1, A2, ... AN]以及一个整数K,请你找出A的最长的完美子数组B,输出B的长度. 如果这样的子数组不存在,输出-1. 输入 第一行包含两个整数N和

倍游趣游戏隐私保护指引

概要欢迎您选择倍游趣游戏!除<倍游趣隐私政策>.<倍游趣游戏许可及服务协议>外,我们还将通过<倍游趣游戏隐私保护指引>(“本指引”)向您进一步细化说明您在使用倍游趣游戏时我们收集.使用.存储和共享个人信息的情况,以及您所享有的相关权利等事宜,本指引是<倍游趣游戏许可及服务协议>的组成部分,其中要点如下: • 为了向您提供游戏娱乐以及与此相关的玩家互动.消费等服务,我们需要收集您的游戏历史.设备信息.登录日志等信息. • 为更好地保护未成年人身心健康,促使未成

zoj 2112 Dynamic Rankings 带修改区间第K大 动态主席树

pass 首先,个人觉得把这个数据结构理解成树状数组套主席树是十分不严谨的.主席树的本质是可持久化权值线段树与前缀和思想的结合.而动态主席树是可持久化权值线段树与树状数组思想的结合.并非树套树般的泾渭分明的叠加. 其次,大概讲下对动态主席树的理解.我们静态主席树中,第i个版本维护的是[1,i]的权值线段树,我们利用前缀和的思想,通过y的版本-x的版本得到[x,y]的权值线段树,从而剥离出一颗对应区间的权值线段树.我们考虑在这个情况下,如果需要修改第a[i]的值,那么从i,i+1,i+2.....

zoj 2112 Dynamic Rankings 动态第k大 线段树套Treap

Dynamic Rankings Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2112 Description The Company Dynamic Rankings has developed a new kind of computer that is no longer satisfied with the query l

zoj 3715 K - Kindergarten Election

一个班有n个小朋友,要选一个班长,(n>=3),每个人不能投自己,给出每个人想要选的人,1号小朋友相当班长,如果一个小朋友不选自己 那么,自己可以给他bi个糖果让他选自己,那么请输出,最少花费多少个糖果 ,1号小朋友可以当上班长 开始的做法是贪心小的,那么问题很复杂,直接枚举小的是不符合条件的 后来想,枚举一号小朋友最后的票为k,那么其他人的票肯定小于等于k-1,如果有小朋友的选票高于k-1,那么先把投这个人的所有小朋友贿赂到小于k-1,按照需要的糖果数量 如果这个时候的选票大于k了,那么显然这