BZOJ2339: [HNOI2011]卡农(dp 容斥)
題意
從$1 - n$中任意選擇一些數,選$m$次構成$m$個集合
保證:
- 集合不為空
- 任意兩個集合不相同
- 集合內各個元素xor起來等于0
Sol
神仙題Orz
我看到兩種做法,一種是洛谷題解上的直接dp,另一種是yyb的神仙轉化。
其實都差不多吧。。
我簡單說一下,設$f[i]$表示選了$i$個集合,滿足條件的方案
直接轉移會非常麻煩,因為要同時限制集合不同 xor不為0,我們又不知道集合的具體元素。
因此我們考慮容斥。
為了方便考慮,我們先不考慮每個元素的位置,最后再除以$M!$
因為xor的性質,若我們已經知道了前$i - 1$個元素,那么我們這時候選什么是確定的。
先確定出前$i - 1$個數,方案數為$A_{2^n - 1}^{i - 1}$,
考慮若此時選了一個空的集合,那我們要保證前$i - 1$個集合滿足條件,方案數為$f[i - 1]$
若選了重復的集合(這是最難理清楚的),剩下的$i - 2$個元素很定要滿足條件,方案數為$f[i - 2]$,然后我們枚舉一個集合,方案數為$2^{n} - (i - 2)$,這樣看似就可以了。但是我們在遞推的時候是沒有考慮順序的,因此另一個元素有$i - 1$種取值,因此還要乘$i - 1$
得到遞推式
f[i]=A_{2^n-1}^{i-1}-f[i-1]-(i-1)\times f[i-2]\times(2^n-1-(i-2))
// luogu-judger-enable-o2 #include<iostream> #include<algorithm> #include<cstdio> #include<stack> #include<vector> #include<cstring> #define LL long long //#define int long long using namespace std; const int MAXN = 3 * 1e6; const LL mod = 1e8 + 7;//fuck inline int read() {char c = getchar(); int x = 0, f = 1;while(c < '0' || c > '9'){if(c == '-') f = -1; c = getchar();}while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();return x * f; } int N, M; LL ifac[MAXN], fac[MAXN], f[MAXN], A[MAXN]; LL fastpow(LL a, LL p) {LL base = 1;while(p) {if(p & 1) base = (base * a) % mod;a = (a * a) % mod; p >>= 1;}return base % mod; } main() {N = read(); M = read(); LL base = fastpow(2, N) % mod;fac[0] = A[0] = 1; for(int i = 1; i <= M; i++) fac[i] = 1ll * i * fac[i - 1] % mod;ifac[M] = fastpow(fac[M], mod - 2);for(int i = 1; i <= M; i++) A[i] = 1ll * A[i - 1] * (base - i + mod) % mod;f[0] = 1; f[1] = 0; for(int i = 2; i <= M; i++) f[i] = ((A[i - 1] - f[i - 1] + mod) % mod - 1ll * f[i - 2] * (i - 1) % mod * (base - i + 1) % mod + mod) % mod;printf("%lld", f[M] * ifac[M] % mod);return 0; } /* 99999 99999 */?
轉載于:https://www.cnblogs.com/zwfymqz/p/9540625.html
總結
以上是生活随笔為你收集整理的BZOJ2339: [HNOI2011]卡农(dp 容斥)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [bzoj2213][Poi2011]D
- 下一篇: python 面向对象(三大特性)