【校内模拟】西行寺无余涅槃(FWT)

在这里插入图片描述
数据范围:


题解:

直接做 FWT 考虑下面这个式子:

F ^ S = ∏ i = 1 n ( ∑ j = 1 k ( − 1 ) ∣ S ∩ p [ i ] [ j ] ∣ a j ) \hat F_S=\prod_{i=1}^n(\sum_{j=1}^k(-1)^{|S\cap p[i][j]|}a_j) F^S=i=1n(j=1k(1)Sp[i][j]aj)

如果裸做 FWT 复杂度是 O ( 2 m m n k ) O(2^mmnk) O(2mmnk),如果直接用上面的式子算出点值然后 IFWT 复杂度是 O ( 2 m n k ) O(2^m n k) O(2mnk),不管怎么做都不太友好。

考虑 ∏ i = 1 m \prod_{i=1}^m\limits i=1m 后面那个括号里面的东西,不难发现对于不同的 i i i,可能的取值只有 2 k 2^{k} 2k 种。

我们强制每个位置把 p [ i ] [ 1 ] p[i][1] p[i][1] 选上,其他的 p [ i ] [ j ] p[i][j] p[i][j] 全部异或上 p [ i ] [ 1 ] p[i][1] p[i][1],最后输出的时候异或回去。这样可能的取值只有 2 k − 1 2^{k-1} 2k1 种。我们只需要对于每一个 F ^ S \hat F_S F^S,计算这 2 k − 1 2^{k-1} 2k1种取值出现了多少次。

然后是一个比较巧妙的构造。

假设我们想要求出 F S , T F_{S,T} FS,T,表示在 F ^ S \hat F_S F^S的表达中, T T T形态出现了多少次。我们可以考虑构造出若干组方程,然后解方程来得到 F S , T F_{S,T} FS,T的值。

解方程的方式可以考虑IFWT,于是考虑构造出 ∑ W ( − 1 ) ∣ W ∩ T ∣ F S , W \sum_{W}(-1)^{|W\cap T|}F_{S,W} W(1)WTFS,W

既然这样,考虑每一种 T T T 该如何贡献到某个 S S S,显然直接在 ⊕ j ∈ T p [ i ] [ j ] \oplus_{j\in T}p[i][j] jTp[i][j] 的位置+1,然后对 S S S 进行 FWT 即可。

证明的话其实问题也不大,考虑 FWT 之前的点值为 H S , T = ∑ i = 1 n [ S = ⊕ j ∈ T p [ i ] [ j ] ] H_{S,T}=\sum_{i=1}^n[S=\oplus_{j\in T}p[i][j]] HS,T=i=1n[S=jTp[i][j]]

FWT 得到 H S ^ , T = ∑ i = 1 n ∏ j ∈ T ( − 1 ) ∣ S ∩ p [ i ] [ j ] ∣ H_{\hat S,T}=\sum_{i=1}^n\prod_{j\in T}(-1)^{|S\cap p[i][j]|} HS^,T=i=1njT(1)Sp[i][j]

F F F 的点值表示为 F S , T = ∑ i = 1 n ∏ j = 1 k − 1 [ [ j ∈ T ] = [ ∣ S ∩ p [ i ] [ j ] ∣ % 2 = 1 ] ] F_{S,T}=\sum_{i=1}^n\prod_{j=1}^{k-1}\left[[j\in T]=[|S\cap p[i][j]|\%2=1]\right] FS,T=i=1nj=1k1[[jT]=[Sp[i][j]%2=1]]

T T T 进行 FWT 可以得到 F S , T ^ = ∑ W ( − 1 ) ∣ W ∩ T ∣ ∑ i = 1 n ∏ j = 1 k − 1 [ [ j ∈ W ] = [ ∣ S ∩ p [ i ] [ j ] ∣ % 2 = 1 ] ] = ∑ i = 1 n ( − 1 ) ∑ j ∈ T ( − 1 ) ∣ S ∩ p [ i ] [ j ] ∣ \begin{aligned} F_{S,\hat T}&=\sum_{W}(-1)^{|W\cap T|}\sum_{i=1}^n\prod_{j=1}^{k-1}\left[[j\in W]=[|S\cap p[i][j]|\%2=1]\right]\\ &=\sum_{i=1}^n(-1)^{\sum_{j\in T}(-1)^{|S\cap p[i][j]|}} \end{aligned} FS,T^=W(1)WTi=1nj=1k1[[jW]=[Sp[i][j]%2=1]]=i=1n(1)jT(1)Sp[i][j]

和上面其实是一样的。


代码:

#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;}
 
你在学习Python数据分析的时候,是否遇到过在这些问题? 别慌!这些都是数据科学入门常见问题。从入门到上手再到解决实际问题,数据科学看似复杂,但如果你掌握了正确的学习方法,完全可以极速入门。 【职场人进阶必备  数据分析/挖掘一点通】 如今的职场上,90%以上的岗位都会涉及数据问题。 以产品文案岗位为例,在一个新产品推向市场之前,文案需要考虑: 此时,可以关注一下市场上已有的相关产品推广数据,如:哪些文案打开率更高?哪些文案转化更好?目标用户的购买习惯如何? 以此作为下一步工作开展的依据,对产品文案工作者来说,可以少走很多弯路。 学会数据分析/挖掘,等于站巨人的肩膀上工作,轻松且高效。 【爬虫、数据分析、数据挖掘知识点三合一】数据问题一网打尽 本课程将知识点悉数融入实战项目,不空谈语法,帮助学员在实践中获取知识,目标是:让学员能自主完成数据采集、数据分析与数据挖掘。 学习完本课程,你可以熟练掌握: 【实战案例超实用,轻松拥有“睡后收入”!】 本课程以股票案例为主线,串联爬虫、数据分析以及数据挖掘多个知识点。 通过实战案例演练,你可以全面掌握股票收益的分析和预判方法,在收获新技能的同时,也有机会获得“睡后收入”! 四大优势: 三重权益:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值