Codeforces 1336E Chiori and Doll Picking (子集和变换、线性基、阈值算法、状压 DP、组合计数)...
題目鏈接
https://codeforces.com/contest/1336/problem/E
題解
假設線性基大小是 \(L\),其異或值域記作 \(S\),則對于異或值域內(nèi)每個數(shù),顯然有 \(2^{n-L}\) 種方案異或得到。因此只需要建一組線性基然后對這個線性基求答案即可,相當于 \(n\le m\).
數(shù)據(jù)分治。
算法一:
暴力枚舉每個元素選不選。
時間復雜度 \(O(2^L)\).
算法二:
記錄非自由元的狀態(tài)進行狀壓 DP.
時間復雜度 \(O(2^{m-L}m^2)\).
結合算法一和算法二,可以通過 E1 題。
算法三:
下面約定某個數(shù)組 FWT 后的數(shù)組用對應的大寫字母表示。
設長為 \(2^m\) 的數(shù)組 \(b_k[i]=[\text{bitcnt}(i)=k]\),\(c[i]=[i\in S]\)。
則 \(k\) 的答案為 \(b_k\) 和 \(c\) 異或卷積后為 \(0\) 的位置上的值,即 \(\frac{1}{2^m}\sum^{2^m-1}_{i=0}B_k[i]C[i]\).
根據(jù) FWT 的定義,易得 \(B_k[i]=\sum^{2^m-1}_{j=0}(-1)^{\text{bitcnt}(i\& j)}[\text{bitcnt}(j)=k]=\sum^{\text{bitcnt}(i)}_{j=0}(-1)^j{\text{bitcnt}(i)\choose j}{m-\text{bitcnt}(i)\choose k-j}\),即 \(B_k[i]\) 只和 \(\text{bitcnt}(i)\) 有關,可以在關于 \(m\) 的多項式時間內(nèi)求出。
現(xiàn)在考慮如何求 \(C\): \(C[i]=\sum_{x\in S} (-1)^{\text{bitcnt}(i\& x)}\),不難觀察到若存在線性基里的一個元素與 \(i\) 的 \(\text{and}\) 的 \(\text{bitcnt}\) 為奇數(shù),則該值一定為 \(0\)(映射法易證),否則為 \(2^L\). 那么只有那些與線性基里的每個元素 \(\text{and}\) 的 \(\text{bitcnt}\) 都為偶數(shù)的 \(i\) 有用。而滿足這個條件的 \(i\) 顯然不能包含任何一個自由元,因此不超過 \(2^{m-L}\) 個,可以直接爆搜。要求的是和 \(B_k\) 點積后的結果,而 \(B_k[i]\) 的取值只和 \(\text{bitcnt(i)}\) 有關,因此只需要對每個 \(\text{bitcnt}\) 統(tǒng)計出 \(C_i\) 的和即可。
時間復雜度 \(O(2^{m-L}+m^3)\).
結合算法一和算法三,可以通過 E2 題。
時間復雜度 \(O(2^{\frac{m}{2}}+m^3+nm)\).
算法三最難想的是第一步吧……異或的性質(zhì)好神奇,Sooke 好強!
代碼
#include<bits/stdc++.h> #define llong long long #define mkpr make_pair #define iter iterator #define riter reversed_iterator #define y1 Lorem_ipsum_dolor using namespace std;inline int read() {int x = 0,f = 1; char ch = getchar();for(;!isdigit(ch);ch=getchar()) {if(ch=='-') f = -1;}for(; isdigit(ch);ch=getchar()) {x = x*10+ch-48;}return x*f; }const int mxN = 1<<19; const int mxM = 53; const int P = 998244353; llong comb[mxM+3][mxM+3]; int bitcnt[mxN+3]; llong a[mxM+3]; int b[mxM+3]; llong ans[mxM+3]; int n,m,sz;llong quickpow(llong x,llong y) {llong cur = x,ret = 1ll;for(int i=0; y; i++){if(y&(1ll<<i)) {y-=(1ll<<i); ret = ret*cur%P;}cur = cur*cur%P;}return ret; }void initfact(int n) {comb[0][0] = 1ll;for(int i=1; i<=n; i++) {comb[i][0] = comb[i][i] = 1ll; for(int j=1; j<i; j++) {comb[i][j] = (comb[i-1][j-1]+comb[i-1][j])%P;}} }int getbitcnt(llong x) {return bitcnt[x&524287]+bitcnt[(x>>19)&524287]+bitcnt[(x>>38)&524287]; }namespace Solve1 {void dfs(int pos,llong x){if(pos==sz) {ans[getbitcnt(x)]++; return;}dfs(pos+1,x); dfs(pos+1,x^a[b[pos]]);} }namespace Solve2 {llong sta[mxM+3];llong f[mxM+3];void dfs(int pos,int cnt,llong x){if(pos==m) {f[cnt+getbitcnt(x)]++; return;}dfs(pos+1,cnt,x); dfs(pos+1,cnt+1,x^sta[pos]);}void solve(){for(int i=sz; i<m; i++){for(int j=0; j<sz; j++){if(a[b[j]]&(1ll<<b[i])) {sta[i] |= (1ll<<j);}}}dfs(sz,0,0ll); // for(int i=0; i<=m; i++) printf("%I64d ",f[i]); puts("");for(int k=0; k<=m; k++){for(int i=0; i<=m; i++){llong coe = 0ll;for(int j=0; j<=i&&j<=k; j++){llong tmp = comb[i][j]*comb[m-i][k-j]%P; if(j&1) {tmp = P-tmp;}coe+=tmp-P,coe+=(coe>>31)&P;}coe = coe*f[i]%P;ans[k]+=coe-P,ans[k]+=(ans[k]>>31)&P;}ans[k] = ans[k]*quickpow((P+1ll)/2ll,m-sz)%P;}} }int main() {initfact(mxM);for(int i=1; i<mxN; i++) bitcnt[i] = bitcnt[i>>1]+(i&1);scanf("%d%d",&n,&m);for(int i=1; i<=n; i++){llong x; scanf("%I64d",&x);for(int k=m-1; k>=0; k--) if(x&(1ll<<k)){if(!a[k]) {a[k] = x; sz++; break;}else {x ^= a[k];}}}for(int i=m-1; i>=0; i--) if(a[i]){for(int j=i+1; j<m; j++) if(a[j]&(1ll<<i)) {a[j] ^= a[i];}} // for(int i=0; i<m; i++) printf("%I64d ",a[i]); puts("");for(int i=0,j=0; i<sz; i++){while(!a[j]) {j++;} b[i] = j; j++;}for(int i=sz,j=0; i<m; i++){while(a[j]) {j++;} b[i] = j; j++;}if(sz<=26){Solve1::dfs(0,0ll);}else{Solve2::solve();}for(int i=0; i<=m; i++) ans[i] = ans[i]*quickpow(2ll,n-sz)%P;for(int i=0; i<=m; i++) printf("%I64d ",ans[i]); puts("");return 0; }總結
以上是生活随笔為你收集整理的Codeforces 1336E Chiori and Doll Picking (子集和变换、线性基、阈值算法、状压 DP、组合计数)...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Codeforces 1149 题解
- 下一篇: Codeforces 1338 题解