2 条题解

  • 0
    @ 2026-9-25 1:33:16

    我必须指出我完全不会博弈论。


    最后一格谁到谁赢,等价于倒数第二格谁到谁输,于是变成丢掉倒数两格一路向后跑,谁不能操作谁输。

    序列移动,常见的刻画方式是对点做差分,把两个点中间的看成石头堆,然后当成阶梯 nim 来做。

    然后你发现这题这么刻画有大问题,这个移动方式非常恶心。

    注意力大爆发!我们考虑把图翻过来考虑,把原图中有石子的点看成空,没石子的点看成有石子。

    然后原先这个长的像跳棋一样的移动方式,经过反转后变成,原先的落点是被向前移动的石子移动前的位置,而原先的起点是被向前移动的石子移动后的位置。

    此时我们发现这个东西变成了标准的序列移动的形状。

    于是套差分和阶梯 nim 即可。蚌埠住了拼尽全力没发现这一块。

    统计第一步的话,注意到走偶数位置的石子也可以扔给对面必败状态,只需要加点加到符合条件即可。

    #include<bits/stdc++.h>
    using namespace std;
    int a[1000005];
    int main(){
        int n,m;
        cin>>m>>n;
        for(int i=1;i<=n;i++)
        cin>>a[i];
        reverse(a+1,a+1+n);
        if(a[1]==m-1){
            for(int i=1;i<=n;i++)
            if(m-i!=a[i]){
                cout<<i-1;
                return 0;
            }
            cout<<n;
            return 0;
        }
        for(int i=1;i<=n;i++)
        a[i]=m-1-a[i];
        vector<int>v;
        vector<pair<int,int>>v2;
        int sum=0,lst=0,qwq=0;
        int flc=0;
        bool flg=0;
        for(int i=1;i<=n;i++){
            if(a[i]==lst+1)qwq++;
            else{
                if(sum&1)
                v.push_back(qwq),flc^=qwq;
                else if(sum){
                    if(flg&&!v.empty())
                    v2.push_back({qwq,*v.rbegin()});
                    else v2.push_back({qwq,0});
                }
                qwq=1;
                sum+=a[i]-lst-1;
                flg=a[i]-lst-1==1;
            }
            lst=a[i];
        }
        if(sum&1)
        v.push_back(qwq),flc^=qwq;
        else{
            if(flg&&!v.empty())
            v2.push_back({qwq,*v.rbegin()});
            else if(sum)v2.push_back({qwq,0});
        }
        int ret=0;
        for(int i:v)
        ret+=i>(flc^i);
        for(pair<int,int>i:v2)
        ret+=(flc^i.second)>i.second&&(flc^i.second)<=i.first+i.second;
        cout<<ret;
        return 0;
    }
    //「差不多该停止了吧,妮戈兰。」
    
    // 欧黛用责备似的声音说道。
    // 妮戈兰转过头,鼓起了脸颊。
    
    //「……真是的,有事等一下再说。
    // 现在可是关系到这孩子愿不愿意再次亲近我的重要时刻。
    // 要是被这孩子讨厌的话,我可是绝对不会原谅学姊你的喔。」
    
    //「我知道,所以我觉得该把这件事告诉你比较好。」
    //「什么事?」
    
    //「那孩子好像快不行了。」
    
    • 0
      @ 2025-10-8 17:05:32
      #include<bits/stdc++.h>
      using namespace std;
      const int N=1e6+10;
      int m,n,a[N],f[N],l[N],len;
      int main()
      {
          scanf("%d%d",&m,&n);
          for(int i=1;i<=n;i++)scanf("%d",&a[i]);
          sort(a+1,a+n+1);a[n+1]=m-1;a[0]=-0x3f3f3f3f;
          if(m-2==a[n]){while(a[n]==a[n-1]+1)n--;n--;}
          if(!n){printf("0\n");return 0;}
          len=1;f[1]=a[n+1]-a[n]-1,l[1]=1;
          for(int i=n-1;i>=1;i--)
          {
              if(a[i]==a[i+1]-1)l[len]++;
              else len++,f[len]=f[len-1]+a[i+1]-a[i]-1,l[len]=1;
          }
          if(a[n]==m-1){printf("%d\n",l[1]);return 0;}
          int ans=0,ss=0;
          for(int i=1;i<=len;i++)if(f[i]%2)ans^=l[i];
          if(!ans){printf("0\n");return 0;}
          for(int i=1;i<=len;i++)
              if(f[i]%2)
              {
                  if(l[i]>=(l[i]^ans)&&(f[i+1]-1!=f[i]))ss++;
              }
              else
              {
                  if(f[i]-1!=f[i-1])
                  {
                      if(l[i]>=ans)ss++;
                  }
                  else if(l[i]+l[i-1]>(l[i-1]^ans))ss++;
              }
          printf("%d\n",ss);
          return 0;
      }
      

      • 1

      【博弈SG】阶梯nim练习2[POI 2004] Gra

      信息

      ID
      3731
      时间
      1000ms
      内存
      128MiB
      难度
      10
      标签
      递交数
      1
      已通过
      1
      上传者