zoukankan      html  css  js  c++  java
  • 洛谷 P5970 [POI2016]Nim z utrudnieniem

    题意

    ( exttt{Nim})游戏,一共(m)颗石子分成了(n)堆,每堆石子数为(a_i),后手可以在游戏开始前扔掉(d)的倍数堆石子,但不能扔掉所有石子,求后手获胜方式有多少种。

    (dleq10,nleq5 imes10^5,a_ileq10^6)(m)不直接给出但保证(mleq10^7)

    思路

    ( exttt{Nim})游戏后手必胜条件:每堆石子的个数异或和为(0)

    (f[i][j][k])表示到第(i)个数,前(i)个数中选出的数的个数( ext{mod} d=j),异或和为(k)的方案数,每次枚举当前堆是否扔掉。

    但是时间复杂度是(O(nmd))的,显然不能过……

    优化需要注意到异或具有的性质:任意个(leq x)的数的异或和(leq2x)。具体来讲就是说任意长度为(k)的数的异或和小于任意长度为(k+1)的数

    因此可以考虑将所有堆的石子数从小到大排序,每次新加入一个数,数的上界一定不会大于(2 imes a_i)

    所以这样时间复杂度就变成了(O(sumlimits_{i=1}^na_id)=O(md))

    但是空间超了,但是只有(kigoplus a_i)(k)之间可以相互转移,所以可以开一个小空间(t),原地完成转移

    还有就是(n)(d)的倍数时会算上全选的情况,此时答案需要减(1)

    常数很大,记得开(O2)

    代码

    /*
    Author:Loceaner
    DP+NIM游戏+状态优化 
    */
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    const int A = 5e5 + 11;
    const int B = (1 << 20) + 11;
    const int mod = 1e9 + 7;
    const int inf = 0x3f3f3f3f;
    
    inline int read() {
      char c = getchar(); int x = 0, f = 1;
      for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
      for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
      return x * f;
    }
    
    int n, d, sum, a[A], t[B], f[10][B], m = 1;
    
    int main() {
      n = read(), d = read();
      for (int i = 1; i <= n; i++) a[i] = read(), sum ^= a[i];
      sort(a + 1, a + 1 + n);
      f[0][0] = 1;
      for (int i = 1; i <= n; i++) {
        while (m <= a[i]) m <<= 1;
        for (int j = 0; j < m; j++) t[j] = f[d - 1][j];
        for (int k = d - 1; k; k--) 
          for (int j = 0; j < m; j++)
            f[k][j] = (f[k][j] + f[k - 1][j ^ a[i]]) % mod;
        for (int j = 0; j < m; j++) f[0][j] = (f[0][j] + t[j ^ a[i]]) % mod;
      }
      cout << (f[0][sum] - (n % d == 0) + mod) % mod << '
    ';
      return 0;
    }
    
  • 相关阅读:
    采用GRE隧道连接不同虚拟机上的mininet网络
    ubuntu下安装Pycharm
    Update to openvswitch 2.3.0
    安装Openvswich 2.3.0
    ubuntu安装git
    解决Vmware Vsphere中虚拟机与本地机复制粘贴问题
    windows下安装python的xlrd和xlwd安装包
    ubuntu 下NetworkX的安装和使用
    大整数乘法 python实现
    推特(Twitter)的Snowflake算法——用于生成唯一ID
  • 原文地址:https://www.cnblogs.com/loceaner/p/13257899.html
Copyright © 2011-2022 走看看