1. 程式人生 > >LOJ2351:[JOI2017/2018決賽]毒蛇越獄——題解

LOJ2351:[JOI2017/2018決賽]毒蛇越獄——題解

In ble calc ace def CI 接下來 試圖 for

https://loj.ac/problem/2351

參考:https://www.cnblogs.com/ivorysi/p/9144676.html

但是參考博客講解太嚇人了,我們換一種通俗易懂的方法講。

首先肯定是能想到容斥和子集和的,但是很尷尬的是,裸容斥的復雜度是O(2^l)的顯然過不去。

我們考慮l特別小,且字符只有三種,話句話講至少有一個字符個數<=6。

那我們就試圖分情況討論,分成以0,1,?為目標特殊處理。

同時我們:

設數組f[0][i]表示討論0時i的二進制1集合屬於j的二進制1集合時sigma(w[j])

設數組f[1][i]表示討論0時j的二進制1集合屬於i的二進制1集合時sigma(w[j])

這兩個數組都能夠在O(2^l)求出,接下來利用他們來導出答案。

PS:令x為原數中0集合,y為原數中1集合,z為原數中?集合。eg:原數101?,x=0100,y=1010,z=0001。

?

最簡單的情況,暴力枚舉即可。

0

枚舉x的子集i。

我們求f[0][i|y]的目的就是將?和0空出來,再將0慢慢填上1達到容斥的效果。

(容斥不太好用語言表述還請見諒,請讀者自行舉例感受容斥。)

顯然我們只填1的時候求的是全集,後面我們就要將0填上1來減去我們將0視為1所帶來的多於的解(以及加上我們多減的)。

所以當當前的數i有偶數個1時要加,反之減。

1

枚舉y的子集i。

我們求f[1][i|z]的目的同理將1和?填上,再將1慢慢填上0達到容斥的效果。

(容斥不太好用語言表述還請見諒,請讀者自行舉例感受容斥。)

顯然我們?和1全填的時候求的是全集,後面我們就要將1填上0來減去我們將1視為0所帶來的多於的解(以及加上我們多減的)。

所以當當前的數i比其y相差k個1時,k為偶要加,反之減。

(總之只要有耐心且不像我這麽傻就能做出來的啦!~)

#include<cmath>
#include<queue>
#include<cstdio>
#include<cctype>
#include<vector>
#include<cstring>
#include
<iostream> #include<algorithm> using namespace std; typedef long long ll; const int L=1048576; int k,q,f[2][L],w[L],calc[L]; char s[L]; int main(){ scanf("%d%d",&k,&q); cin>>s; for(int i=0;i<(1<<k);i++)w[i]=f[0][i]=f[1][i]=s[i]-0; for(int i=0;i<(1<<k);i++)calc[i]=calc[i>>1]+(i&1); for(int i=1;i<(1<<k);i<<=1){ for(int j=0;j<(1<<k);j++){ if(j&i)f[1][j]+=f[1][j^i],f[0][j^i]+=f[0][j]; } } while(q--){ cin>>s; int x=0,y=0,z=0,ans=0; for(int i=0;i<k;i++){ if(s[i]==0)x|=(1<<(k-i-1)); else if(s[i]==1)y|=(1<<(k-i-1)); else z|=(1<<(k-i-1)); } if(calc[x]<=6){ for(int i=x;;i=(i-1)&x){ if(calc[i]&1)ans-=f[0][i|y]; else ans+=f[0][i|y]; if(!i)break; } }else if(calc[y]<=6){ for(int i=y;;i=(i-1)&y){ if(calc[i^y]&1)ans-=f[1][i|z]; else ans+=f[1][i|z]; if(!i)break; } }else{ for(int i=z;;i=(i-1)&z){ ans+=w[i|y]; if(!i)break; } } printf("%d\n",ans); } return 0; }

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+歡迎訪問我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

LOJ2351:[JOI2017/2018決賽]毒蛇越獄——題解