CF1530F

正难则反,考虑计算每条线都不全为一的概率 \(P\)

对角线很烦,考虑先 \(2^2\) 容斥掉,直接把概率改为一即可

于是就有了一个暴力容斥的解法:钦定全为一的行列集合 \(S\),则 \(P=\sum_{S}(-1)^{\lvert S\rvert}\prod_{(i,j)\in S}p_{i,j}\),时间复杂度 \(O(2^{2n}n^2)\)

考虑将行分出来,设全为一的行集合为 \(S_1\),全为一的列集合为 \(S_2\),则 \(P=\sum_{S_1}\sum_{S_2}(-1)^{\lvert S_1\rvert+\lvert S_2\rvert}\prod_{i\in S_1\lor j\in S_2}p_{i,j}\)

\(=\sum_{S_1}(-1)^{\lvert S_1\rvert}(\prod_{i\in S_1}p_{i,j})\sum_{S_2}(-1)^{\lvert S_2\rvert}\prod_{j\in S_2\land i\notin S_1}p_{i,j}\)

\(g_{j,S}=\prod_{i\notin S}p_{i,j},f_{S}=(-1)^{\lvert S\rvert}\prod_{i\in S}p_{i,j}\)

\(=\sum_{S_1}f_{S_1}\sum_{S_2}(-1)^{\lvert S_2\rvert}\prod_{j\in S_2}g_{j,S_1}\)

\(G_{j,S}=-g_{j,S}\)

\(=\sum_{S_1}f_{S_1}\sum_{S_2}\prod_{j\in S_2}G_{j,S_1}\)

现在相当于有数列 \(a\),要求所有集合的元素积的和,答案是 \(\prod (a_i+1)\)

\(=\sum_{S_1}f_{S_1}\prod(G_{j,S_1}+1)\)

时间复杂度 \(O(n2^n)\)

#include<bits/stdc++.h>
using namespace std;
namespace ax_by_c{
const int mod=31607;
const int INV10000=3973;
const int N=23;
const int S=1<<22;
int lb(int x){
	return x&(-x);
}
int n,p[N][N],mxst;
int pct[S],lg2[S];
int vis1[N],vis2[N];
int row[N];
int f[S],g[N][S];
int cal(){
	for(int i=1;i<=n;i++){
		row[i]=1;
		for(int j=1;j<=n;j++){
			row[i]=row[i]*p[i][j]%mod;
		}
	}
	f[0]=1;
	for(int i=1;i<=mxst;i++){
		f[i]=f[i^lb(i)]*row[lg2[lb(i)]]%mod;
	}
	for(int i=0;i<=mxst;i++){
		if(pct[i]%2==1){
			f[i]=mod-f[i];
		}
	}
	for(int j=1;j<=n;j++){
		g[j][mxst]=1;
		for(int s=mxst-1;s>=0;s--){
			g[j][s]=g[j][s|lb(~s)]*p[lg2[lb(~s)]][j]%mod;
		}
		for(int s=0;s<=mxst;s++){
			g[j][s]=mod-g[j][s];
		}
	}
	int res=0;
	for(int s=0;s<=mxst;s++){
		int mul=1;
		for(int j=1;j<=n;j++){
			mul=mul*(g[j][s]+1)%mod;
		}
		res=(res+f[s]*mul)%mod;
	}
	return res;
}
void main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			scanf("%d",&p[i][j]);
			p[i][j]=p[i][j]*INV10000%mod;
		}
	}
	mxst=(1<<n)-1;
	for(int i=1;i<=mxst;i++){
		pct[i]=pct[i>>1]+(i&1);
	}
	for(int i=1;i<=n;i++){
		lg2[1<<(i-1)]=i;
	}
	int P=0;
	for(int x=0;x<=1;x++){
		int mul=1;
		if(x){
			for(int i=1;i<=n;i++){
				mul=mul*p[i][i]%mod;
				vis1[i]=p[i][i];
				p[i][i]=1;
			}
		}
		for(int y=0;y<=1;y++){
			int muls=mul;
			if(y){
				for(int i=1;i<=n;i++){
					muls=muls*p[i][n-i+1]%mod;
					vis2[i]=p[i][n-i+1];
					p[i][n-i+1]=1;
				}
			}
			if(x^y){
				P=(P-muls*cal()%mod+mod)%mod;
			}
			else{
				P=(P+muls*cal()%mod)%mod;
			}
			if(y){
				for(int i=1;i<=n;i++){
					p[i][n-i+1]=vis2[i];
				}
			}
		}
		if(x){
			for(int i=1;i<=n;i++){
				p[i][i]=vis1[i];
			}
		}
	}
	printf("%d\n",(1-P+mod)%mod);
}
}
int main(){
	ax_by_c::main();
	return 0;
}
posted @ 2024-09-16 14:40  ax_by_c  阅读(16)  评论(0)    收藏  举报