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

Posted cly-none

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了做题TCSRM601 Div1 500 WinterAndSnowmen——按位考虑&dp相关的知识,希望对你有一定的参考价值。

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

题意:求有多少对集合(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))

#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 ; ++ 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;
}


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


以上是关于做题TCSRM601 Div1 500 WinterAndSnowmen——按位考虑&dp的主要内容,如果未能解决你的问题,请参考以下文章

特定字符串的正则表达式匹配,例如 Ord(500) Ord(601) Ord(537)

TopCoder SRM500 Div1 250 其他

TopCoder SRM502 Div1 500 贪心 01背包

topcoder srm 500 div1

Topcoder SRM 563 Div1 500 SpellCards

TopCoder SRM420 Div1 500pt RedIsGood