題解:
直接做 FWT 考慮下面這個式子:
如果裸做 FWT 複雜度是 ,如果直接用上面的式子算出點值然後 IFWT 複雜度是 ,不管怎麼做都不太友好。
考慮 後面那個括號裏面的東西,不難發現對於不同的 ,可能的取值只有 種。
我們強制每個位置把 選上,其他的 全部異或上 ,最後輸出的時候異或回去。這樣可能的取值只有 種。我們只需要對於每一個 ,計算這 種取值出現了多少次。
然後是一個比較巧妙的構造。
假設我們想要求出,表示在的表達中,形態出現了多少次。我們可以考慮構造出若干組方程,然後解方程來得到的值。
解方程的方式可以考慮IFWT,於是考慮構造出。
既然這樣,考慮每一種 該如何貢獻到某個 ,顯然直接在 的位置+1,然後對 進行 FWT 即可。
證明的話其實問題也不大,考慮 FWT 之前的點值爲
FWT 得到
而 的點值表示爲
對 進行 FWT 可以得到
和上面其實是一樣的。
代碼:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
namespace IO{
inline char gc(){
static cs int Rlen=1<<22|1;static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}template<typename T>T get_integer(){
char c;while(!isdigit(c=gc()));T x=c^48;
while(isdigit(c=gc()))x=x*10+(c^48);return x;
}inline int gi(){return get_integer<int>();}
char obuf[30000007],*oh=obuf;
template<typename T>void print(T a,char c=' '){
static char ch[23];int tl=0;
do ch[++tl]=a%10; while(a/=10);
while(tl)*oh++=ch[tl--]^48;*oh++=c;
}struct obuf_flusher{~obuf_flusher(){fwrite(obuf,1,oh-obuf,stdout);}}Flusher;
}using namespace IO;
using std::cerr;
using std::cout;
cs int mod=998244353;
inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(int a,int b){return a-b<0?a-b+mod:a-b;}
inline int mul(int a,int b){ll r=(ll)a*b;return r>=mod?r%mod:r;}
inline void Inc(int &a,int b){a+=b-mod;a+=a>>31&mod;}
inline void Dec(int &a,int b){a-=b;a+=a>>31&mod;}
inline void Mul(int &a,int b){a=mul(a,b);}
inline int po(int a,int b){int r=1;for(;b;b>>=1,Mul(a,a))if(b&1)Mul(r,a);return r;}
inline void ex_gcd(int a,int b,int &x,int &y){
if(!b){x=1,y=0;return;}ex_gcd(b,a%b,y,x);y-=a/b*x;
}inline int inv(int a){int x,y;ex_gcd(mod,a,y,x);return x+(x>>31&mod);}
int n,m,k;
void FWT(int *A,int S){
for(int re i=1;i<S;i<<=1)
for(int re j=0;j<S;j+=i<<1)
for(int re k=0;k<i;++k){
int x=A[j+k],y=A[i+j+k];
A[j+k]=add(x,y),A[i+j+k]=dec(x,y);
}
}void IFWT(int *A,int S){
FWT(A,S);int iS=inv(S);
for(int re i=0;i<S;++i)Mul(A[i],iS);
}
cs int N=1e6+7;int S,T,xr;
int a[11],p[N][11],G[1<<10|7],H[1<<20|7];
int vl[1<<10|7],*f[1<<19|7];
void Main(){
n=gi(),m=gi(),k=gi();
for(int re i=0;i<k;++i)a[i]=gi();
S=1<<m;T=1<<(k-1);
for(int re s=0;s<T;++s){vl[s]=a[0];
for(int re i=1;i<k;++i)
(s>>(i-1)&1)?Dec(vl[s],a[i]):Inc(vl[s],a[i]);
}
for(int re i=1;i<=n;++i){
for(int re j=0;j<k;++j)p[i][j]=gi();
for(int re j=1;j<k;++j)p[i][j]^=p[i][0];
xr^=p[i][0];
}for(int re s=0;s<T;++s){
memset(H,0,sizeof(int)*S);
for(int re i=1;i<=n;++i){
int ps=0;
for(int re j=1;j<k;++j)
if(s&(1<<(j-1)))ps^=p[i][j];
++H[ps];
}FWT(H,S);f[s]=new int[S];
for(int re i=0;i<S;++i)f[s][i]=H[i];
}for(int re i=0;i<S;++i){
for(int re s=0;s<T;++s)G[s]=f[s][i];
FWT(G,T);H[i]=1;
for(int re s=0;s<T;++s)Mul(H[i],po(vl[s],G[s]>>(k-1)));
}IFWT(H,S);for(int re i=0;i<S;++i)print(H[i^xr],' ');
}
inline void file(){
#ifdef zxyoi
freopen("yuyuko.in","r",stdin);
#endif
}
signed main(){file();Main();return 0;}