[THUPC2019]找树

题意

  • 给定一个无向图,定义一个生成树的权值为按位(oplus_{o_i})的结果
  • 求最大的生成树

先将问题转化一下,把求最大的生成树,转化为存不存在某个权值的生成树,于是就可以利用(matrix-tree)定理求出某个权值的生成树的个数,但这里的边权可以先按照(oplus_{o_i})的规则fwt一下,最后再将行列式的值ifwt回来

#include<bits/stdc++.h>
#define For(i, a, b) for(int i = (a), en = (b); i <= en; ++i)
#define Rof(i, a, b) for(int i = (a), en = (b); i >= en; --i)
#define Tra(u, i) for(int i = hd[u]; ~i; i = e[i].net)
#define cst const
#define LL long long
#define DD double
#define LD long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define inf 0x3f3f3f3f
#define Inf 0x3f3f3f3f3f3f3f3f
#define eps 1e-12
#define mod 998244353
#define maxn 70
using namespace std;

int n, m, w, a[maxn + 5], lim, inv2;
int fp(int x, int y){
	int asi = 1;
	while(y){
		if(y & 1) asi = 1ll * asi * x % mod;
		x = 1ll * x * x % mod;
		y >>= 1;
	}
	return asi;
}
struct Pol{
	int x[4096];
	void out(){
		For(i, 0, lim - 1) cout << x[i] << " ";
		cout << endl;
	}
	void fwt(int ty){
		for(int i = 2, now = 0; i <= lim; i <<= 1, now++){
			int ii = i >> 1;
			for(int j = 0; j < lim; j += i){
				For(p, j, j + ii - 1){
					if(!ty){
						int tem = x[p], tem1 = x[p + ii];
						if(a[now] == 0)	x[p] = (tem + tem1) % mod;
						if(a[now] == 1) x[p + ii] = (tem + tem1) % mod;
						if(a[now] == 2){
							x[p] = (tem - tem1 + mod) % mod;
							x[p + ii] = (tem + tem1) % mod;
						}
					}
					else{
						int tem = x[p], tem1 = x[p + ii];
						if(a[now] == 0) x[p] = (tem - tem1 + mod) % mod;
						if(a[now] == 1) x[p + ii] = (tem1 - tem + mod) % mod;
						if(a[now] == 2){
							x[p] = 1ll * inv2 * (tem + tem1) % mod;
							x[p + ii] = 1ll * inv2 * (tem1 - tem + mod) % mod;
						}
					}
				}
			}
		}
	}
} zer;
Pol operator + (cst Pol &x, cst Pol &y){Pol asi; For(i, 0, lim - 1) asi.x[i] = (x.x[i] + y.x[i]) % mod; return asi;}
Pol operator - (cst Pol &x, cst Pol &y){Pol asi; For(i, 0, lim - 1) asi.x[i] = (x.x[i] - y.x[i] + mod) % mod; return asi;}
Pol operator * (cst Pol &x, cst Pol &y){Pol asi; For(i, 0, lim - 1) asi.x[i] = 1ll * x.x[i] * y.x[i] % mod; return asi;}
Pol operator / (cst Pol &x, cst Pol &y){Pol asi; For(i, 0, lim - 1) asi.x[i] = 1ll * x.x[i] * fp(y.x[i], mod - 2) % mod; return asi;}
bool operator ! (cst Pol &x){For(i, 0, lim - 1) if(x.x[i]) return 0; return 1;}
struct Mat{
	Pol x[maxn + 5][maxn + 5];
	Pol get_det(){
		int k = 0;
		Pol asi;
		For(i, 0, lim - 1) asi.x[i] = 1;
		For(i, 1, n - 1){
			if(!x[i][i]){
				k++;
				For(j, i + 1, n - 1){
					if(!x[j][i]) continue;
					For(p, i, n - 1) swap(x[i][p], x[j][p]);
					break;
				}
			}
			if(!x[i][i]) return zer;
			asi = asi * x[i][i];
			For(j, i + 1, n - 1){
				Pol tem = x[j][i] / x[i][i];
				For(p, i, n - 1) x[j][p] = x[j][p] - tem * x[i][p];
			}
		}
		if(k & 1) For(i, 0, lim - 1) asi.x[i] = mod - asi.x[i];
		return asi;
	}
} ma;

template <class T>
void read(T &x){
	char ch;
	bool ok;
	for(ok = 0, ch = getchar(); !isdigit(ch); ch = getchar()) if(ch == '-') ok = 1;
	for(x = 0; isdigit(ch); x = x * 10 + ch - '0', ch = getchar());
	if(ok) x = -x;
}

char s[maxn + 5];
int main(){
	//freopen("19.in", "r", stdin);
	inv2 = fp(2, mod - 2);
	read(n); read(m);
	scanf("%s",s); w = strlen(s);
	For(i, 0, w - 1){
		if(s[i] == '|') a[i] = 1;
		if(s[i] == '^') a[i] = 2;
	}
	lim = 1 << w;
	For(i, 1, m){
		int u, v, wi; read(u); read(v); read(wi);
		ma.x[u][v].x[wi]--;
		ma.x[v][u].x[wi]--;
		ma.x[u][u].x[wi]++;
		ma.x[v][v].x[wi]++;
	}
	For(i, 1, n - 1) For(j, 1, n - 1){
		if(i ^ j) For(p, 0, lim - 1) ma.x[i][j].x[p] = (ma.x[i][j].x[p] + mod) % mod;
		ma.x[i][j].fwt(0);
	}
	Pol tem = ma.get_det();
	tem.fwt(1);
	Rof(i, lim - 1, 0) if(tem.x[i]){printf("%d
", i); return 0;}
	puts("-1");
	return 0;
}
原文地址:https://www.cnblogs.com/lprdsb/p/13791495.html