首先這個題可以記憶化搜尋,不過直接記憶化複雜度是不能滿分的,需要加可行性剪枝:就是當前的狀態肯定無解時,就要直接返回。
#include
using
namespace std;
const
int maxn=
55,lim=(1
<<21)
-1;inline
intread()
while
(isdigit
(c))
return t*f;
}int n,a[maxn]
,cho[maxn]
,ans,suf[maxn]
;struct pii};
bool
operator
<
(pii a,pii b)
maplong
long
> mp[55]
;int alfa1,alfa2;
long
long
dfs(
int now,
int tmp1,
int tmp2)if(
(alfa2&tmp1)
!=alfa2)
pii tmp=
pii(tmp1,tmp2);if
(mp[now]
[tmp])if
(now==n+1)
return0;
}long
long ans=0;
ans+
=dfs
(now+
1,tmp1&a[now]
,tmp2)
; ans+
=dfs
(now+
1,tmp1,tmp2&a[now]);
mp[now]
[tmp]
=ans;
return ans;
}int
main()
然後正解是按位容斥,具體就是觀察這些數的二進位制,然後考慮不合法的情況是什麼:對於某一位二進位制,如果所有在這一位是1的數都被選進了乙個集合,那這個情況就不合法,直接算不好算,所以需要o(2
20)列舉
欽定哪些
位不合法
的狀態o(2^)列舉欽定哪些位不合法的狀態
o(220)
列舉欽定
哪些位不
合法的狀
態容斥,係數就是−1不
合法的位
數-1^
−1不合法的
位數,然後此時有乙個問題,就是不能有乙個集合是全空的,所以一開始所有不滿足條件的方案數不是2
n2^n
2n.容斥過程中的方案數也沒有那麼簡單。具體看**
#include
using
namespace std;
#define int long long
inline
intread()
while
(isdigit
(c))
return t*f;
}int n,a[55]
;bitset<
55> alfa[25]
,beta[25]
,a,b,c,w;
int len,pos[25]
,ans;
void
dfs(
int now,
int w,bitset<
55> a,bitset<
55> b,bitset<
55> c)
dfs(now+
1,w*(-
1),a&alfa[pos[now]
],b|beta[pos[now]
],c)
;//將所有0加入b集合
dfs(now+
1,w*(-
1),a&alfa[pos[now]
],b,c|beta[pos[now]])
;//將所有0加入c集合
dfs(now+
1,w,a,b,c);}
signed
main()
} len=0;
for(
int i=
0;i<
20;i++)}
for(
int i=
1;i<=n;i++
)a[i]=1
;dfs(1
,1,a,b,c)
;printf
("%lld\n"
,ans-1)
;//兩個集合都沒有限制的情況在上面的dfs中沒有考慮
return0;
}
一道互動練習題
的做法 考慮逐位確定 對於每個位置,往後列舉有沒有位置可以使得正確位置更多,如果有,那麼有兩種情況,1是這個位置被放到了正確的位置,2是這個位置本來應該放的數被放來了 這裡的重點是我們需要區分1和2 具體的做法是記下讓這個位置答案正確位置數變大的2個位置,將其和i一起移位 這裡是手繪示意圖.即把p1...
一道fft練習題
考場上想到的o n 2 o n 2 o n2 暴力 記f i j f i j f i j 表示前i個位置,長度為j的連擊出現的期望次數 記g i j g i j g i j 表示第到i個位置為止,目前連擊次數為j的概率 轉移時有一些細節 include using namespace std con...
一道sam練習題
考慮答案實際上是每個子串的出現次數的平方和.這個可以通過手玩樣例驗證.考慮廣義sam 先將所有字串建成trie,然後再在trie上bfs,建出sam.考慮fail樹 每次插入乙個新節點,會改變從這個節點開始到根的路徑上的每個節點的right集合大小.所以考慮樹剖維護這種操作,然後每乙個單詞的答案就是...