題目
題目描述
ZYB是一名資深特級OI教師。在他的題庫裏,一共有M道判斷題。現在,他正在教授N名OI選手,作爲一名特級教師,他一眼就看出了每個學生對每道問題的答案是YES還是NO.
現在他希望出一場堂測,他會選擇這些判斷題當中的一個非空子集(2M−1種可能)。他希望這場堂測能有一些區分度。定義一道題目有區分度,當且僅當至少有一個學生回答YES,並且至少有一個學生回答NO,而一場堂測有區分度,當且僅當所有的題目都是有區分度的。
然而,這些學生有可能會咕咕咕。每個學生只有50%的可能出現在這堂課上進行堂測。現在ZYB想知道,對於每個不同的子集,有多大的概率這場堂測是有區分度的呢?
爲了方便起見,假設這2M−1個概率分別是Ans1,Ans2,…,Ans2M−1,你只需要輸出(Ans1×2Nmod998244353)xor(Ans2×2Nmod998244353)xor…xor(Ans2M−1×2Nmod998244353)的值.
輸入格式
第一行兩個整數n,m.
接下來n行,每行一個長度爲m的01字符串,其中第i位爲1表示該學生對這個問題回答YES,0表示回答NO.
輸出格式
一行輸出所求值。
樣例1
輸入
2 2
01
10
輸出
1
解釋 對於每道題目,當且僅當所有人都到時纔有區分度.故Ans1=Ans2=Ans3=1/4,帶入可知是1.
樣例2
輸入
4 2
00
01
10
11
輸出
7
解釋 對於第一題,當只有1,2或只有3,4到時是沒區分度的,所以可能性是(16-7)/16,第二題也是如此.
若需要兩題都有區分度,則需要1,4同時到或2,3同時到,則(1,4),(2,3)以及任意超過3個人到都是合法解。可能性爲7/16.
於是,答案爲9 xor 9 xor 7=7
數據範圍
對於30%的數據,M≤4.
對於60%的數據,M≤10.
對於100%的數據,N≤100000,M≤15
思路
我們考慮設表示裏面的這些題目都有區分度的方案數。
那麼我們可以知道,其中是的一個 子集,而的含義是有多少種方案使得中的所有題都沒有區分度.
最後我們考慮如何計算。我們設計一個,是一個長度爲的三進制數,如果第位爲表示這一位無所謂,然後如果 這一位爲則表示這一位選擇的數的個數. 設是中不爲的位置集合,則,最後再給每個加上空集就行。
如何計算?如果中沒有,則可以直接算出來,否則我們隨便找一個,將這個分別變成得到,,,按照的個數從小往大枚舉就 行,兩步的複雜度都是,總複雜度爲
代碼
#include<bits/stdc++.h>
#define N 300005
#define Mo 998244353
using namespace std;
int f[15000005],n,pw3[N],pw2[N],g[1<<15],m,size[N],Cas;
char c[N];
void dfs(int u,int _2,int _3,int _4)
{
if (u==m)
{
if (_4!=-1)
f[_3]=f[_3-pw3[m-1-_4]]+f[_3-2*pw3[m-1-_4]];
(g[_2]+=pw2[f[_3]]-1)%=Mo;
}
else
{
dfs(u+1,(_2<<1)+1,_3*3,_4);
dfs(u+1,(_2<<1)+1,_3*3+1,_4);
dfs(u+1,(_2<<1),_3*3+2,u);
}
}
int main()
{
pw2[0]=1;
for(int i=1; i<N;++i) pw2[i]=pw2[i-1]*2%Mo;
for(int i=1; i<(1<<15);++i) size[i]=size[i/2]+(i&1);
pw3[0]=1;
for(int i=1; i<20;++i) pw3[i]=pw3[i-1]*3;
scanf("%d%d",&n,&m);
for(int i=1; i<=n;++i)
{
scanf("%s",c); int tmp=0;
for(int j=0;j<m;++j) tmp=tmp*3+(c[j]=='1');
f[tmp]++;
}
dfs(0,0,0,-1); int yjy=0;
for(int i=0; i<(1<<m);++i) (g[i]+=1)%=Mo;
for(int i=1; i<(1<<m);++i)
{
int tmp=0;
for(int j=i;;j=(j-1)&i)
{
if (size[j]&1) tmp=(tmp-g[j]+Mo)%Mo;
else tmp=(tmp+g[j])%Mo;
if (!j) break;
}
yjy^=tmp;
}
printf("%d\n",yjy);
}