[JOI 2018 Final]毒蛇越獄
阿新 • • 發佈:2022-03-23
\[題意:給你一個S,每個位置上為0/1/?\\
讓你求ans = \sum_{S可能出現}f_S\\
詢問次數很多,每次要做到O(2^6)
\]
sol.
考慮\(S <= 20\),考慮鴿巢原理
\[min\{cnt_0,cnt_1,cnt_{?}\} <= 6 \]考慮一下幾種情況
\(1.cnt_0\)最小
\[ans = \sum_{S\in S_0}(-1)^{|S|}g_{S ^ S_1} \]\(1.cnt_1\)最小
\[ans = \sum_{S\in S_1}(-1)^{|S|}f_{S \oplus S_1 | f_{?}} \]\(1.cnt_?\)最小
\[ans = \sum_{S\in S_{?}}a_{S \oplus S_1} \]其中\(f_S,g_S\)分別是原來的高維字首字尾和
#include<bits/stdc++.h> #define MAXN 2000005 typedef long long ll; using namespace std; int L,Q; void fwt1(ll f[] , int tp){ for(int j = 0 ; j < L ; j++){ for(int S = 0 ; S < (1 << L) ; S++){ if(S & (1 << j)){ f[S] = f[S] + f[S ^ (1 << j)]; } } } } void fwt2(ll f[] , int tp){ for(int j = 0 ; j < L ; j++){ for(int S = (1 << L) - 1 ; S >= 0 ; S--){ if((S & (1 << j)) == 0)f[S] = f[S] + f[S ^ (1 << j)]; } } } ll f[MAXN],g[MAXN],cnt[MAXN],pl[MAXN],a[MAXN]; int maxS; int S1,S2,S3;//0 , 1 , ? int cnt1,cnt2,cnt3; char s[MAXN]; int main(){ //freopen("01-03.in" , "r" , stdin); scanf("%d%d" , &L , &Q); scanf("%s" , s + 1); for(int i = 0 ; i < (1 << L) ; i++){ f[i] = (s[i + 1] - '0'); g[i] = (s[i + 1] - '0'); a[i] = (s[i + 1] - '0'); } fwt1(f , 1); fwt2(g , 1); for(int i = 0 ; i < (1 << L) ; i++)cnt[i] = cnt[i >> 1] + (i & 1); pl[0] = 1;for(int i = 1 ; i < (1 << L) ; i++){ if(i & 1)pl[i] = pl[i >> 1] * (-1); else pl[i] = pl[i >> 1]; } maxS = (1 << L) - 1; while(Q--){ ll ans = 0; S1 = S2 = S3 = 0; scanf("%s" , s + 1); for(int i = 1 ; i <= L ; i++){ if(s[L - i + 1] == '0')S1 |= (1 << (i - 1)); if(s[L - i + 1] == '1')S2 |= (1 << (i - 1)); if(s[L - i + 1] == '?')S3 |= (1 << (i - 1)); } cnt1 = cnt[S1] , cnt2 = cnt[S2] , cnt3 = cnt[S3]; if(cnt3 <= min(cnt1 , cnt2)){ for(int S = S3 ; ; S = S3 & (S - 1)){ ans = ans + a[S | S2]; if(S == 0)break; } } else if(cnt1 <= min(cnt2 , cnt3)){ for(int S = S1 ; ; S = S1 & (S - 1)){ ans = ans + pl[S] * g[S2 | S]; if(S == 0)break; } } else if(cnt2 <= min(cnt1 , cnt3)){ for(int S = S2 ; ; S = S2 & (S - 1)){ ans = ans + pl[S] * f[(S2 ^ S) | S3]; if(S == 0)break; } } cout<<ans<<endl; } }