「ZJOI2019」开关

「ZJOI2019」开关

神题


前言

\(\text{FWT}_{\oplus}(F(x))=F'(x)\)

关于\(\text{FWT}_{\oplus}\)的展开式子,我发现大部分人都不晓得。。。。

\([x^S]F'(x)=\sum_T(-1)^{|S\cap T|} [x^T]F(x)\)

\(F(x)=\frac{F''(x)}{2^n}\)

详细可以看这个

定义\(\bigoplus\)为两个多项式的异或卷积

\(\times\)为两个多项式对应项直接相乘

\([x^S]F(x)\)表示\(F(x)\)的第\(S\)项的系数


正文

翻转过程是一个\(\oplus\)的过程,所以考虑用集合幂指数配合\(\text{FWT}_\oplus\)构造和求解方程

事实上问题等价于从初始状态\(S\)跑到\(\empty\)的期望次数

设从\(S\)\(\empty\)的期望次数生成函数为\(F(x)\),其中\([x^{\empty}]F(x)=0\)

设转移函数\(G(x),[x^{\{i\}}]G(x)=p_i\)

那么我们的方程就是\(F(x)\bigoplus G(x)+\sum x^S+cx^{\empty}=F(x)\)

其中\(x^S\)表示这次转移之后答案要加一

由于直接这样转移得到的方程显然是无穷解的,因为无法保证\([x^{\empty}]F(x)=0\)

所以我们用一个常数项\(cx^{\empty}\)平衡这个问题,\(c\)现在是未知的

\(\because F(x)\bigoplus G(x)+\sum x^S+cx^{\empty}=F(x)\)

\(\therefore (F(x)\bigoplus G(x)+\sum x^S+cx^{\empty})'=F'(x)\)

\(\therefore F'(x)\times G'(x)+(\sum x^S+cx^{\empty})'=F'(x)\)

我们模拟一下\(G'(x)\)

\([x^S]G'(x)=\sum_i(-1)^{|S\cap \{i\}|}[x^{\{i\}}]G(x)=\sum_{i\notin S}p_i-\sum_{i\in S}p_i\)

再卷一下\((\sum x^S+cx^{\empty})'\)

\((\sum x^S)'=\sum_S\sum_T(-1)^{|S\cap T|}x^S\)

\(\because (-1)^{|S\cap T|} =\sum_{T\subset S}(-1)^|T|\cdot 2^{n-|S|}=[S=\empty]2^{n-|S|}\)

\(\therefore (\sum x^S)'=2^n x^{\empty}\)

\((cx^{\empty})'=\sum c\cdot x^S\)

然后我们带入反解\([x^S]F'(x)\)


\(S=\empty\)时,

\([x^S]F'(x)\cdot [x^S]G'(x)+2^n+c=[x^S]F'(x)\)

然后发现此时\([x^S]G'(x)=1\),那么就意味着\(2^n+c=0\)

解出了\(c=-2^n\),但是此时我们实际上并不知道\([x^{\empty}]F'(x)\)的值


\(S\ne \empty\)

\([x^S]F'(x)\cdot [x^S]G'(x)+c=[x^S]F'(x)\)

\([x^S]F'(x)(1-[x^S]G'(x))=c\)

\[[x^S]F'(x)=-\frac{2^n}{1-\sum_{i\notin S}p_i+\sum_{i\in S}p_i}=-\frac{2^n}{2\sum_{i\in S}p_i} \]


我们考虑要求出\([x^\empty]F'(x)\)的值

\([x^{\empty}]F(x)=2^{-n}\cdot \sum [x^S] F'(x)=0\)

\[[x^\empty]F'(x)-\sum_{S\ne \empty}\frac{2^n}{2\sum_{i\in S}p_i}=0 \]

那么我们由\(F'(x)\)回代得到\([x^S]F(x)(S \ne \empty)\)


\[[x^S]F(x)=2^{-n}\cdot \sum_T(-1)^{|S\cap T|}[x^T]F'(x) \]

\[=2^{-n}([x^\empty]F'(x)+\sum_{T\ne \empty}(-1)^{|S\cap T|}[x^T]F'(x)) \]

\[=\sum_{T\ne\empty}\frac{1}{2\sum_{i\in T}p_i}+2^{-n}\sum_{T\ne \empty}(-1)^{|S\cap T|}[x^T]F'(x) \]

\[=\sum_{T\ne \empty,|S\cap T|\mod 2=1} \frac{1}{\sum_{i\in T} p_i} \]

下面是一个背包,跑的同时统计一下就好了\(|S\cap T|\)的奇偶性就好了

然后会发现事实上并没有必要特判\(S=\empty\)的情况

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cctype>
#include<vector>
using namespace std;

#define reg register
typedef long long ll;
#define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)

#define pb push_back
template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); }
template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); }

char IO;
int rd(){
	int s=0;
	int f=0;
	while(!isdigit(IO=getchar())) if(IO=='-') f=1;
	do s=(s<<1)+(s<<3)+(IO^'0');
	while(isdigit(IO=getchar()));
	return f?-s:s;
}

const int N=5e4,P=998244353;


int n;
int s[N],a[N],sum;
int dp[110][N][2]; // 背包表示p之和为i,有j个不同的方案数
ll Inv[N]; 
ll c;

ll qpow(ll x,ll k) {
	ll res=1;
	for(;k;k>>=1,x=x*x%P) if(k&1) res=res*x%P;
	return res;
} 



int main(){
	freopen("switch.in","r",stdin),freopen("switch.out","w",stdout);
	n=rd();
	rep(i,1,n) s[i]=rd();
	dp[0][0][0]=1;
	rep(i,1,n) {
		int x=rd();
		rep(j,0,sum) rep(k,0,1) rep(d,0,1) 
			dp[i][j+d*x][k^(d&&s[i])]=(dp[i][j+d*x][k^(d && s[i])]+dp[i-1][j][k])%P;
		sum+=x;
	}
	Inv[0]=Inv[1]=1;
	rep(i,2,sum) Inv[i]=(P-P/i)*Inv[P%i]%P;
	ll ans=0;
	rep(i,1,sum) ans=(ans+Inv[i]*dp[n][i][1])%P; // 因为最后统计的时候没有空集,所以i从1开始
	printf("%lld\n",ans*sum%P);
}





原文地址:https://www.cnblogs.com/chasedeath/p/12969126.html