zoukankan      html  css  js  c++  java
  • poj1900 Game

    http://poj.org/problem?id=1900

    一道有意思的很好的题目。

    A,S,P三个人玩一个游戏。A先宣布一个正整数N(2<=N<=200),然后选择两个不同的正整数x,y(1<=x,y<=N),然后把x+y的值告诉S,把x*y的值告诉P。

    接下来S和P轮流告诉对方自己现在是否知道这两个数是多少,S先开始。例如:

    S和P都已知N=10,S知道x+y=9,P知道x*y=18。

    S:我不知道x和y的值。

    P:我也不知道。

    S:我还不知道。

    P:我仍然不知道。

    S:我现在知道了,x=3,y=6.

    给定N和M(两人总共说“我不知道”的次数,0<=M<=100),求所有可能的x和y。

    乍一看,很神奇是吧?

    我们来分析一下,3和6这个数据太大了(我刚开始分析了半天才看出了策略),先来看一些更简单的例子:

    如果N=10,S知道x+y=3.可能的组合只有3=1+2. 毫无疑问x=1,y=2. 这样只要M=0次就能猜出来了。

    如果N=10,x+y=8,x*y=7:

    首先S知道所有可能的组合有8=2+6=3+5. S不知道到底是哪一种。

    然后P知道所有可能的组合只有7=1*7. 因此x=1,y=7. 这样只要M=1次就猜出来了。

    再如N=10,x+y=4,x*y=4.

    首先S所有可能的组合为4=1+3=2+2. S还不知道。

    然后P所有可能的组合为4=1*4=2*2. P也还不知道。

    接下来又是S。他已经知道P在上一次没有猜出来,而如果x=1,y=3,那么P所知道的数应该为3,从而他应该在上一次就猜出来了。

    所以4=1+3这种组合是错的。因此S知道,只有4=2+2一种可能。这样只要M=2次就可以猜出来了。

    从以上例子我们可以得到一个结论:如果在第M次“不知道”后,某个人所知道的全部组合ALL中只有一种还没有猜出来(也就是说其余的所有组合形式都可以在M次之内猜出来),那么这一种就是答案无疑了。相反,如果在M次之后,仍然有多于一种情况都没有猜出来,显然也就无法决定到底是这些情况中的哪一种了。

    根据这种策略,只要从m=0从小到大枚举,对每种x,y,根据M的奇偶性把x+y或x*y进行分解,看是否只有x,y这一种情况没有还猜出来。然后再M次之后,看所有xy的组合,那种可以在M次之后猜出来即可。

    这道题的时限卡得很紧,有两点需要注意:

    第一,如果某次在m次之后没有任何一个xy被更新的话,接下来m再怎么变大也不会有变动了(事实上有的状态无论多少次都猜不出来)。直接break

    第二,x*y如果每次都分解一遍的话会被模和除运算卡掉。在开始预处理一下才行。

    注:我这道题第一天看想出了正确解法,但是没注意到x和y不相等这个条件,得到的答案不对,所以搁置了两个星期。。今天拾起来再提。

    刚开始WA掉了因为以为只有x=1,y=2这种情况是M=0的(其实N=10,x+y=19这种也是啊)。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<string>
     4 #include<cstring>
     5 #include<algorithm>
     6 #include<cmath>
     7 using namespace std;
     8 
     9 const int N = 205;
    10 int n,f[N][N],tot[N*N];
    11 pair<int,int> fac[N*N][15]/*15试出来的,否则MLE*/;
    12 
    13 int search(int a,int b,int dep)
    14 {//搜索j,k是否要i次才能猜出来
    15     int s = a+b,p = a*b,i,flag = 1;
    16     if(dep%2==0) {
    17         for(i = 1; i+i<s; i++)
    18             if(i!=a && s-i<=n && f[i][s-i]>=dep) {
    19                 flag = 0; break;
    20             }
    21         if(flag) f[a][b] = dep;
    22     }
    23     else {
    24         for(i = 1; i<=tot[p]; i++)
    25             if(fac[p][i].first!=a && f[fac[p][i].first][fac[p][i].second]>=dep) {
    26                 flag = 0; break;
    27             }
    28         if(flag) f[a][b] = dep;
    29     }
    30     return f[a][b]==dep;
    31 }
    32 
    33 void preset() 
    34 {
    35     for(int i = 1; i<n; i++)
    36         for(int j = i+1; j<=n; j++) {
    37             tot[i*j]++;
    38             fac[i*j][tot[i*j]] = make_pair(i,j);
    39         }
    40 }
    41 
    42 int main()
    43 {
    44     int i,j,k,m,ans = 0;
    45     cin >> n >> m;
    46     memset(f, 0x3f, sizeof(f));
    47     preset();
    48     for(i = 0; i<=m; i++) {
    49         int flag = 0;
    50         for(j = 1; j<=n; j++)
    51             for(k = j+1; k<=n; k++)
    52                 if(f[j][k]>m)
    53                     flag |= search(j,k,i);
    54         if(!flag) break;
    55     }
    56     for(i = 1; i<=n; i++)
    57         for(j = i+1; j<=n; j++)
    58             if(f[i][j]==m) ans++;
    59     printf("%d\n", ans);
    60     for(i = 1; i<=n; i++)
    61         for(j = i+1; j<=n; j++)
    62             if(f[i][j]==m) printf("%d %d\n", i,j);
    63     return 0;
    64 }
    View Code
  • 相关阅读:
    ubuntu远程windows桌面
    spring boot 给返回值加状态 BaseData
    spring boot 拦截异常 统一处理
    IntelliJ IDEA spring boot 远程Ddbug调试
    IntelliJ IDEA 常用插件
    spring boot 请求地址带有.json 兼容处理
    spring boot 接口返回值去掉为null的字段
    spring boot 集成disconf
    Spring boot 自定义拦截器
    Linux下安装MySQL
  • 原文地址:https://www.cnblogs.com/liuaohan/p/5554126.html
Copyright © 2011-2022 走看看