洛谷 P5406

题面传送门

首先看到这道题你必须要有一个很清楚的认识:这题新定义的 (oplus) 符号非常奇怪,也没有什么性质而言,因此无法通过解决最优化问题的思路来解决这个问题,只好按照计数题的思路来解决,即考虑 (cnt_k) 表示权值为 (k) 的生成树的个数,那么我们即求最大的满足 (cnt_k e 0)(k)

考虑怎样维护这个东西,首先考虑一个非常 trivial 的情况,如果题目中求生成树权值的方法不是这个奇怪的 (oplus) 运算而是加法怎么办。那么对于一条权值为 (w) 的边,如果它在生成树中,它会对生成树权值产生 (w) 的贡献,因此很自然地想到用幂级数表示权值,即将每条边看作一个幂级数 (x^w),然后跑矩阵树定理会得出一个幂级数 (F(x)),那么权值为 (v) 的生成树棵数就是 ([x^v]F(x))

接下来考虑将加法换为二进制运算后怎样处理,我们还是将每条边看作一个幂级数 (x^w),那么与之前唯一的区别是,原来幂级数 (x^u)(x^v) 乘积的贡献会累加到 (x^{u+v}) 上,即加法卷积,现在 (x^u)(x^v) 的乘积则会累加到 (x^{u|v})(或者 (x^{u&v}),或 (x^{uoperatorname{xor}v}))上,即二进制卷积。看到二进制卷积我们很自然地想到一个东西——FWT,因此如果题目中的 (oplus) 只是 (operatorname{and})(operatorname{or})(operatorname{xor}) 的话,那么我们就可以一遍 FWT,再求出基尔霍夫矩阵解出每种权值的行列式,再 IFWT 回去求出所有的 (cnt_k)。而现在对于新定义的 (oplus) 运算,虽然它每一位的运算规律都不同,但由于它们彼此之间互相独立,并且都是二进制运算,因此 FWT 对于该运算依然适用,具体来说对于每一位如果它是 ^ 就按照 FWTxor/IFWTxor 的套路合并,&,| 也同理,这样即可求出最终的 (cnt_k)

时间复杂度 (2^wn^3),可以通过此题。记得模上一个大质数,为了防止冲突我取了 (993244853)(请求出生成树个数模 (993244853) 等于 (0) 的概率(大雾))。

const int MOD=993244853;
const int INV2=496622427;
const int MAXN=70;
const int MAXV=1<<12;
int qpow(int x,int e){
	int ret=1;
	for(;e;e>>=1,x=1ll*x*x%MOD) if(e&1) ret=1ll*ret*x%MOD;
	return ret;
}
void add(int &x,int v){((x+=v)>=MOD)&&(x-=MOD);}
int n,m,k;char s[14];
int a[MAXN+5][MAXN+5][MAXV+5],b[MAXV+5];
void FWT(int *a,int type){
	for(int i=2,lg=0;lg<k;i<<=1,++lg){
		for(int j=0;j<(1<<k);j+=i)
			for(int l=0;l<(i>>1);l++){
				if(s[lg]=='|'){
					if(~type) add(a[(i>>1)+j+l],a[j+l]);
					else add(a[(i>>1)+j+l],MOD-a[j+l]);
				} else if(s[lg]=='&'){
					if(~type) add(a[j+l],a[(i>>1)+j+l]);
					else add(a[j+l],MOD-a[(i>>1)+j+l]);
				} else {
					int X=a[j+l],Y=a[(i>>1)+j+l];
					if(~type) a[j+l]=(X+Y)%MOD,a[(i>>1)+j+l]=(X-Y+MOD)%MOD;
					else a[j+l]=1ll*INV2*(X+Y)%MOD,a[(i>>1)+j+l]=1ll*INV2*(X-Y+MOD)%MOD;
				}
			}
	}
}
int getdet(int x){
	int sgn=1;
	for(int i=1;i<n;i++){
		int t=i;
		for(int j=i+1;j<n;j++) if(a[j][i][x]) t=j;
		for(int j=i;j<n;j++) swap(a[i][j][x],a[t][j][x]);
		if(t^i) sgn=-sgn;
		int iv=qpow(a[i][i][x],MOD-2);
		for(int j=i+1;j<n;j++){
			int mul=1ll*(MOD-iv)*a[j][i][x]%MOD;
			for(int l=i;l<n;l++) a[j][l][x]=(a[j][l][x]+1ll*mul*a[i][l][x])%MOD;
		}
	} int res=(sgn+MOD)%MOD;
//	for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) printf("%d%c",a[i][j][x]," 
"[j==n]);
	for(int i=1;i<n;i++) res=1ll*res*a[i][i][x]%MOD;
	return res;
}
int main(){
	scanf("%d%d%s",&n,&m,s);k=strlen(s);
	for(int i=1,u,v,w;i<=m;i++){
		scanf("%d%d%d",&u,&v,&w);--u;--v;
		add(a[u][v][w],MOD-1);add(a[v][u][w],MOD-1);
		add(a[u][u][w],1);add(a[v][v][w],1);
	}
	for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) FWT(a[i][j],1);
//	for(int i=0;i<(1<<k);i++){
//		for(int u=1;u<n;u++) for(int v=1;v<n;v++)
//			printf("%d%c",a[u][v][i]," 
"[v==n]);
//		printf("
");
//	}
	for(int i=0;i<(1<<k);i++) b[i]=getdet(i)/*,printf("%d
",b[i])*/;
	FWT(b,-1);for(int i=(1<<k)-1;~i;i--) if(b[i]) return printf("%d
",i),0;
//	assert(114514^1919810^114514^1919810);
	puts("-1"); 
	return 0;
}
原文地址:https://www.cnblogs.com/ET2006/p/luogu-P5406.html