【做题】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 \bigcap T = \emptyset\),且\(S\)中所有元素的異或和小于\(T\)中所有元素的異或和。對\(10^9+7\)取模。
\(n,m \leq 2000\)
首先,通過記錄當前兩個集合的異或和,轉移時考慮每個元素的3種選擇,容易得到\(O(n^3)\)的暴力dp。然而,要對此優化卻是一件困難的事情。
但無論如何,對狀態的優化的必要的。因此,我們就必須避免同時記錄兩個集合的異或和。考慮兩個異或和如果只有一位,那么它們的大小關系就能通過記錄一位來得到。而對于多位的二進制數的大小比較,我們也只用比較不同的最高位就可以了。
因此,我們枚舉不同的最高位。那么,我們就可以忽略后面的位,并只用記錄我們所枚舉的這一位。剩下的問題就在于保證更高的位是相等的。那可以用記錄兩個數在更高位上的異或和實現,異或和為0,這兩個數就是相等的。
時間復雜度\(O(n^2\log 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; }小結:雖然是“思維訓練”中的題,但也會有自己沒有掌握的技巧。
轉載于:https://www.cnblogs.com/cly-none/p/9695526.html
總結
以上是生活随笔為你收集整理的【做题】TCSRM601 Div1 500 WinterAndSnowmen——按位考虑dp的全部內容,希望文章能夠幫你解決所遇到的問題。