• 【做题】TCSRM601 Div1 500 WinterAndSnowmen——按位考虑&dp


    原文链接https://www.cnblogs.com/cly-none/p/9695526.html

    题意:求有多少对集合(S,T)满足:(S subseteq {1,2...n }, T subseteq {1,2...m},S igcap T = emptyset),且(S)中所有元素的异或和小于(T)中所有元素的异或和。对(10^9+7)取模。

    (n,m leq 2000)

    首先,通过记录当前两个集合的异或和,转移时考虑每个元素的3种选择,容易得到(O(n^3))的暴力dp。然而,要对此优化却是一件困难的事情。

    但无论如何,对状态的优化的必要的。因此,我们就必须避免同时记录两个集合的异或和。考虑两个异或和如果只有一位,那么它们的大小关系就能通过记录一位来得到。而对于多位的二进制数的大小比较,我们也只用比较不同的最高位就可以了。

    因此,我们枚举不同的最高位。那么,我们就可以忽略后面的位,并只用记录我们所枚举的这一位。剩下的问题就在于保证更高的位是相等的。那可以用记录两个数在更高位上的异或和实现,异或和为0,这两个数就是相等的。

    时间复杂度(O(n^2log n))

    upd18.9.25

    确实如zhouzhendong所说,这是(O(n^2))的。下面代码已修改。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 2060, MOD = (int)(1e9 + 7);
    int dp[N][N][2],n,m,len,ans;
    
    class WinterAndSnowmen {
    public:
      int getNumber( int N, int M );
    };
    int WinterAndSnowmen::getNumber(int N, int M) {
      n = N, m = M;
      len = max(n,m);
      for (int s = 1 ; s <= 12 ; ++ s) {
        memset(dp,0,sizeof dp);
        dp[0][0][0] = 1;
        for (register int i = 1 ; i <= len ; ++ i) {
          for (register int j = 0 ; j < (2048 >> (s-1)) ; ++ j) {
            for (int k = 0 ; k < 2 ; ++ k) {
              if (i <= n)
                (dp[i][j^(i>>(s-1))][k] += dp[i-1][j][k]) %= MOD;
              if (i <= m)
                (dp[i][j^(i>>(s-1))][k ^ ((i >> (s-1))&1)] += dp[i-1][j][k]) %= MOD;
              (dp[i][j][k] += dp[i-1][j][k]) %= MOD;
            }
          }
        }
        (ans += dp[len][1][1]) %= MOD;
      }
      return ans;
    }
    

    小结:虽然是“思维训练”中的题,但也会有自己没有掌握的技巧。

  • 相关阅读:
    F5 BIG-IP之一前期随笔(应用交付网络产品)
    F5 BIG-IP LTM负载均衡策略
    OA-APP增加空间
    如何在Windows服务器上新建一个Powershell.ps1的定时任务
    领益科技:查询AD中被锁定的账号并进行解锁
    使用Python创建简单的HTTP和FTP服务器
    Mysql binlog日志太多,占用大量磁盘空间该如何正确处理
    【vspher运维】ESXI 日志文件
    【vsphere运维】ESXI命令行操作虚拟机
    内容图片切换
  • 原文地址:https://www.cnblogs.com/cly-none/p/9695526.html
Copyright © 2020-2023  润新知