[JOI 2018 Final]毒蛇越狱
\[题意:给你一个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;
}
}

浙公网安备 33010602011771号