多校训练1 A Alice and Bob 博弈

  • 比赛时推了个假规律……但大体就是先求必败态全集,然后所有属于这个集合里的输入都是先手必败,其余情况先手胜。
  • 首先发现{ 3 , 2 } 先手必败,{ 2 , 3 } 也是,(现在省略对称部分),那么,所有可以一步推导为
    {3, 2 } 的就是先手必胜。能一步推导为{ 3 , 2 } 的状态{ x , y } 有一个规律:( x − 2 ) ∣ ( y − 3 ) 或( x − 3 ) ∣ ( y − 2 ) (a ∣ b 代表a可以整除b, b = ka)
  • 通过{ 3 , 2 } 这个状态,可以得到{ 7 , 5 } 也是先手必败,把{ 7 , 5 } 也加入到集合中,之后,不断利用已有的必败状态,推导出新的必败状态。
  • 打个表把结果存在数组里。

思路:打表,将所有必败态情况都存入数组mp[maxn][2]里,必败态的两堆石子具有对称性,在判断前将石子堆n, m中较大堆赋给n,我们在存必败态时就只考虑堆成状态中n较大的一类即可。
把必败态存入数组中,然后开两重for循环不断判断该条件下是否能一步转换成已有的必败态,不能的话即存入数组中。

打表代码:

  • 补题的时候wa了两发,但是对比发现,和题解给出的数组长度也一致,目测存的数也对的样子……然后大无语事件出现了,为了之后输出的结果可直接复制粘贴存入数组里(因为输出一行满了它会自动换行,不能直接用,后面还得手动删),设置一行产生5个元素,然后进行换行操作,但是没设置好,当cnt == 5时没有输出到……orz
#include <stdio.h>
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5010;
int mp[maxn][2];
int tot;

//求必败态全集,将所有可以一步转化为必败态的排除 
bool check(int x, int y)
{
   
        //要考虑到所有情况 
        if(x % y == 0 || y % x == 0 || x== y)
                return false;//一步获胜,先手赢
        int a, b;
        for(int i = 0; i < tot; i++)
        {
   
                a = x - mp[i][0];
                b = y - mp[i][1];
                //注意a,b不能是负数,a和b为倍数关系 (或a,b中一个为0)
                if(a == 0 || b == 0)
                        return false;
                if(a > 0 && b > 0 && (a % b == 0 || b % a == 0))
                        return false;

                a = x - mp[i][1];
                b = y - mp[i][0];
                if(a == 0 || b == 0)
                        return false;
                if(a > 0 && b > 0 && (a % b == 0 || b % a == 0))
                        return false; 
        }
        return true;
}

int main()
{
   
        tot = 1;
        mp[0][0] = 3;
        mp[0][1] = 2;
        for(int i = 1; i <= 5000; i++)
        {
   
                for(int j = 1; j < i; j++)
                {
   
                        if(check(i, j))
                        {
   
                                mp[tot][0] = i, mp[tot][1] = j;
                                tot++;
                        }
                }
        }
        int cnt = 0; 
        for(int i = 1; i < tot; i++)
        {
   
                if(cnt == 5)
                {
   
                        cout<<endl;
                        cnt = 0;
                }
                cout<<"{"<<mp[i][0]<<","<<mp[i][1]<<"},";
                cnt++;
        }
        cout<<endl;
        cout<<tot<<endl;
        
        return 0;
}

Like this,然后直接全选复制进数组里存起来,在输出时顺便把长度 tot 打出来,后面给数组分配比 tot 稍大一点的空间。
在这里插入图片描述
之后就是判断每组输入是否为必败态即可。
accode:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1400; 

int mp[maxn][2] = {
   
{
   3,2},{
   7,5},{
   12,9},{
   15,11},{
   20,14},{
   22,17},
{
   32,24},{
   33,19},{
   35,26},{
   38,31},{
   40,29},{
   52,42},
{
   53,37},{
   58,28},{
   60,45},{
   62,50},{
   65,47},{
   68,55},
{
   70,49},{
   75,44},{
   79,57},{
   86,67},{
   87,64},{
   92,72},
{
   99,74},{
   101,77},{
   110,83},{
   113,85},{
   116,90},{
   118,82},
{
   123,89},{
   126,97},{
   127,95},{
   129,94},{
   136,103},{
   145,108},
{
   146,106},{
   156,139},{
   160,122},{
   161,120},{
   164,125},{
   166,112},
{
   174,81},{
   177,133},{
   180,138},{
   182,132},{
   186,143},{
   190,142},
{
   195,149},{
   197,152},{
   198,135},{
   199,105},{
   203,148},{
   215,168},
{
   218,158},{
   224,172},{
   228,171},{
   229,163},{
   232,154},{
   236,185},
{
   239,141},{
   241,192},{
   246,115},{
   253,184},{
   256,194},{
   259,189},
{
   264,208},{
   266,201},{
   268,188},{
   271,210},{
   274,207},{
   278,214},
{
   280,221},{
   281,205},{
   286,170},{
   289,217},{
   298,179},{
   301,226},
{
   305,252},{
   306,248},{
   307,234},{
   309,131},{
   313,245},{
   315,223},
{
   317,213},{
   321,250},{
   322,212},{
   325,244},{
   327,220},{
   332,231},
{
   339,255},{
   340,151},{
   346,261},{
   350,176},{
   358,276},{
   359,263},
{
   362,285},{
   367,293},{
   370,283},{
   372,238},{
   375,270},{
   379,288},
{
   386,296},{
   390,295},{
   391,243},{
   408,319},{
   411,312},{
   415,303},
{
   432,300},{
   435,329},{
   445,345},{
   446,343},{
   449,338},{
   454,334},
{
   456,291},{
   461,352},{
   464,311},{
   467,349},{
   470,384},{
   474,395},
{
   478,361},{
   479,357},{
   483,400},{
   485,388},{
   487,399},{
   489,337},
{
   494,364},{
   496,342},{
   501,324},{
   505,377},{
   509,374},{
   511,397},
{
   518,393},{
   520,369},{
   521,273},{
   525,423},{
   527,366},{
   529,421},
{
   530,407},{
   531,405},{
   532,356},{
   537,413},{
   541,420},{
   545,336},
{
   549,434},{
   553,382},{
   556,443},{
   557,419},{
   558,348},{
   560,427},
{
   565,258},{
   568,410},{
   570,431},{
   574,437},{
   577,355},{
   580,425},
{
   586,417},{
   588,402},{
   590,354},{
   596,460},{
   600,440},{
   601,404},
{
   603,439},{
   610,469},{
   614,448},{
   620,453},{
   624,430},{
   632,473},
{
   635,492},{
   639,381},{
   646,499},{
   648,508},{
   649,504},{
   651,452},
{
   653,503},{
   658,516},{
   660,481},{
   661,463},{
   664,515},{
   666,466},
{
   671,459},{
   673,498},{
   683,442},{
   691,477},{
   693,564},{
   697,551},
{
   702,331},{
   711,555},{
   716,514},{
   719,429},{
   722,595},{
   723,543},
{
   726,491},{
   735,540},{
   737,567},{
   740,523},{
   744,572},{
   748,585},
{
   752,539},{
   760,476},{
   761,472},{
   766,576},{
   768,583},{
   771,563},
{
   772,458},{
   776,513},{
   778,634},{
   780,579},{
   785,628},{
   787,619},
{
   788,507},{
   799,626},{
   800,548},{
   805,594},{
   810,607},{
   811,593},
{
   818,622},{
   822,617},{
   825,547},{
   827,644},{
   828,599},{
   831,616},
{
   836,630},{
   842,612},{
   845,606},{
   849,609},{
   
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值