zoukankan      html  css  js  c++  java
  • FZYZ-2071 A Simple Math Problem IX

    P2071 -- A Simple Math Problem IX

    时间限制:1000MS      内存限制:262144KB

    状态:Accepted      标签:    数学问题-博弈论   无   无

    Description

    给定a,b,n,保证a≥2,b≥1,a^b≤n。两个人在玩游戏,每个人每次可以把a加1,或者把b加1,但是不能违反a^b<=n,无法再进行操作的人就输掉了这一场游戏。

    假设两个人都足够聪明,按照最优策略进行游戏,问先手是否有必胜策略。

    Input Format

    第一行两个正整数 n 和 m。

    接下来 m 行,每行两个正整数 a 和 b。保证 a≥2,b≥1,a^b≤n。

    Output Format

    m 行,如果对于这一对数字 a 和 b,如果先手有必胜策略,输出 “Yes”。否则输出 “No” (不含引号)

    Sample Input

    5 3
    2 1
    2 2
    3 1

    Sample Output

    Yes
    No
    No

    Hint

    对于10%的数据,n=2

    对于70%的数据,n<=1000

    对于100%的数据,n<=10^9,m<=10^5

    题解

          不难想到,状态(a,b)可以转移到状态(a + 1, b)或者(a, b + 1)。设F[a][b]为该局面下先手胜败,1表示必胜,0表示必败,那么F[a][b] = (F[a + 1][b] & F[a][b +1]) ^ 1。但是数据范围太大,该怎么办呢?

          首先,a和b必须满足a^b <= n,即log (a, n) >= b,又因为a >= 2,所以log (2, n) >= log(a, n),所以b <= log (2, n) <= 30。

          其次,a^b <= n还可以推出当b >= 2时,a <= sqrt(n),这也是一个不大的数字。当b=1时,即便n很大,但随着a的递增,可供选择的b会逐渐减少,最后转移会变成一条链,所以根据奇偶性判断就好。

    代码

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <cmath>
     4 #include <cstring>
     5 #define MAXN 50010
     6 #define MAXM 50
     7 using namespace std;
     8 
     9 int N, M;
    10 int j;
    11 long long X;
    12 int A, B;
    13 int Lim;
    14 bool F[MAXN][MAXM];
    15 
    16 char ch; int aa, bb;
    17 int Scan() {
    18     while(ch=getchar(),(ch<'0'||ch>'9')&&ch!='-');
    19     ch=='-' ? (bb=1,aa=0) : (aa=ch-48,bb=0);
    20     while(ch=getchar(),ch>='0'&&ch<='9')aa=aa*10+ch-48;
    21     if(bb)aa=-aa;
    22     return aa;
    23 }
    24 
    25 int main() {
    26     memset(F, 1, sizeof(F)); //F必须开bool 
    27     N = Scan();
    28     Lim = int (sqrt(N));
    29     if ((Lim + N) & 1) F[Lim + 1][1] = 0;
    30     for (int i = Lim; i >= 2; --i) {
    31         for (j = 0, X = 1; X <= N; X *= i, ++j); //X可能会爆int 
    32         for (--j; j; --j) F[i][j] = (F[i + 1][j] & F[i][j + 1]) ^ 1;
    33     }
    34     for (M = Scan(); M; --M) {
    35         A = Scan(); B = Scan();
    36         if (B == 1 && A > Lim) {
    37             if ((N + A) & 1) printf("Yes
    ");
    38             else printf("No
    ");
    39         }
    40         else {
    41             if (F[A][B]) printf("Yes
    ");
    42             else printf("No
    ");
    43         }
    44     }
    45 }
  • 相关阅读:
    javascript线性渐变2
    javascript无缝滚动2
    javascript Object对象
    javascript无缝滚动
    javascript图片轮换2
    javascript图片轮换
    用C/C++写CGI程序
    linux shell 的 for 循环
    重磅分享:微软等数据结构+算法面试100题全部答案完整亮相
    查看linux服务器硬盘IO读写负载
  • 原文地址:https://www.cnblogs.com/DonMaestro/p/4324207.html
Copyright © 2011-2022 走看看