题解 [CF468E] Permanent / 归田

传送门
[CF468E] Permanent

考虑将 \(A_{i, p_i}=w\) 转化为一条连接 \(i, p_i\),权值为 \(w\) 的边
那么问题转化为二分图完美匹配
\(w_i\) 拆为两条边 \((w_i-1), 1\)
这样任意两个点之间都至少有一条权为 1 的边
这样的好处是解除了完美匹配的限制,任意一个匹配都可以产生贡献
那么答案是

\[\sum\limits_{s是一个匹配}(n-|s|)!\prod\limits_{i\in s}(w_i-1) \]

然后算后面那个东西
现在有 \(O(2k)\) 个点
考虑对每个连通块分别处理
每个块内有 \(\leqslant k\) 条边所以有 \(\leqslant k+1\) 个点
然后又是二分图所以一定有一边有 \(\leqslant\frac{k}{2}\) 个点
然后就有了一个 \(O(k2^k)\) 的做法

然后考虑另一个处理方式
若连通块内有 \(m\) 条边,先找一棵生成树出来
\(O(2^{m-n+1})\) 枚举非树边的选择情况,然后在生成树上 DP 匹配
复杂度 \(O(n^22^{m-n+1})\)

将两个做法拼在一起,复杂度 \(O(k^22^{\frac{k}{3}})\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 2000010
#define fir first
#define sec second
#define pb push_back
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, k;
ll fac[N];
#undef unix
const ll mod=1e9+7;
int x[N], y[N], w[N];
int unix[N], uniy[N], sta[N], xsiz, ysiz;
inline void md(ll& a, ll b) {a+=b; a=a>=mod?a-mod:a;}
inline ll qpow(ll a, ll b) {ll ans=1; for (; b; a=a*a%mod,b>>=1) if (b&1) ans=ans*a%mod; return ans;}

// namespace task1{
// 	int now;
// 	ll f[2][55], ans;
// 	map<int, int> mp;
// 	map<int, ll> val;
// 	void solve() {
// 		int cnt=0;
// 		for (int i=1; i<=k; ++i) ++mp[y[i]], val[y[i]]=(val[y[i]]+w[i])%mod;
// 		for (int t=0; t<=mp.size(); ++t) {
// 			// cout<<"t: "<<t<<endl;
// 			memset(f[now], 0, sizeof(f[now]));
// 			f[now][0]=1; int cnt=0;
// 			for (auto it:mp) {
// 				memset(f[now^1], 0, sizeof(f[now^1]));
// 				// cout<<"it: ("<<it.fir<<','<<it.sec<<")"<<endl;
// 				// cout<<"val: "<<val[it.fir]<<endl;
// 				for (int i=0; i<=t; ++i) {
// 					ll tem=1;
// 					bool flag=cnt==i;
// 					for (int j=n-t-(cnt-i)-flag; j>n-t-(cnt-i)-flag-it.sec; --j)
// 						tem=tem*j%mod;
// 					f[now^1][i]=(f[now^1][i]+f[now][i]*tem)%mod;
// 					tem=val[it.fir];
// 					for (int j=n-t-(cnt-i); j>n-t-(cnt-i)-it.sec+1; --j)
// 						tem=tem*j%mod;
// 					f[now^1][i+1]=(f[now^1][i+1]+f[now][i]*tem)%mod;
// 				}
// 				// cout<<"f: "; for (int k=0; k<=t; ++k) cout<<f[now^1][k]<<' '; cout<<endl;
// 				cnt+=it.sec; now^=1;
// 			}
// 			ll tem=f[now][t];
// 			for (int i=n-cnt; i; --i) tem=tem*i%mod;
// 			// cout<<"add: "<<tem<<endl;
// 			ans=(ans+tem)%mod;
// 		}
// 		printf("%lld\n", ans);
// 	}
// }

// namespace force{
// 	#undef unix
// 	ll f[2][1<<20], ans;
// 	vector<pair<int, int>> buc[N];
// 	int unix[N], uniy[N], sta[N], xsiz, ysiz, now;
// 	void solve() {
// 		for (int i=1; i<=k; ++i) {
// 			unix[++xsiz]=x[i];
// 			uniy[++ysiz]=y[i];
// 		}
// 		sort(unix+1, unix+xsiz+1);
// 		sort(uniy+1, uniy+ysiz+1);
// 		xsiz=unique(unix+1, unix+xsiz+1)-unix-1;
// 		ysiz=unique(uniy+1, uniy+ysiz+1)-uniy-1;
// 		for (int i=1; i<=k; ++i) {
// 			x[i]=lower_bound(unix+1, unix+xsiz+1, x[i])-unix;
// 			y[i]=lower_bound(uniy+1, uniy+ysiz+1, y[i])-uniy;
// 			buc[x[i]].pb({y[i]-1, w[i]}), sta[x[i]]|=1<<y[i]-1;
// 		}
// 		if (ysiz>20) {task1::solve(); exit(0);}
// 		int lim=1<<ysiz;
// 		f[now][0]=1;
// 		for (int i=1; i<=xsiz; ++i,now^=1) {
// 			memset(f[now^1], 0, sizeof(f[now^1]));
// 			for (int s=0; s<lim; ++s) {
// 				f[now^1][s]=(f[now^1][s]+f[now][s]*(n-ysiz-(i-__builtin_popcount(s)-1)))%mod;
// 				for (auto& it:buc[i]) if (!(s&(1<<it.fir)))
// 					f[now^1][s|(1<<it.fir)]=(f[now^1][s|(1<<it.fir)]+f[now][s]*it.sec)%mod;
// 				for (int j=0; j<ysiz; ++j) if (!(s&(1<<j)) && !(sta[i]&(1<<j)))
// 					md(f[now^1][s|(1<<j)], f[now][s]);
// 			}
// 		}
// 		for (int s=0; s<lim; ++s) ans=(ans+f[now][s])%mod;
// 		for (int i=n-xsiz; i; --i) ans=ans*i%mod;
// 		printf("%lld\n", (ans%mod+mod)%mod);
// 	}
// }

namespace task2{
	bool intr[105][105], vis[N];
	vector<pair<int, int>> to[N];
	int id1[N], id2[N], rk[N], sub[N], tot, siz;
	ll f[2][1<<22], dp[105][2][55], tem[2][55], g[N], h[N], t[N], ans;
	vector<pair<vector<int>, vector<int>>> sta;
	void dfs(int u, int col, pair<vector<int>, vector<int>>& tem) {
		vis[u]=1;
		(col?tem.fir:tem.sec).pb(u);
		for (auto& v:to[u]) if (!vis[v.fir])
			dfs(v.fir, col^1, tem);
	}
	void solve1(pair<vector<int>, vector<int>>& it) {
		int lim=1<<it.fir.size(), now=0;
		for (int s=0; s<lim; ++s) f[now][s]=0;
		for (int i=0; i<it.fir.size(); ++i) rk[it.fir[i]]=i;
		f[now][0]=1;
		for (auto& u:it.sec) {
			// cout<<"u: "<<u<<endl;
			for (int s=0; s<lim; ++s) f[now^1][s]=f[now][s];
			for (int s=0; s<lim; ++s) if (f[now][s]) {
				for (auto& v:to[u]) if (!(s&(1<<rk[v.fir]))) {
					// cout<<"v: "<<v.fir<<' '<<v.sec<<endl;
					f[now^1][s|(1<<rk[v.fir])]=(f[now^1][s|(1<<rk[v.fir])]+f[now][s]*v.sec)%mod;
				}
			}
			now^=1;
		}
		// cout<<"f: "; for (int s=0; s<lim; ++s) cout<<f[now][s]<<' '; cout<<endl;
		// cout<<"g: "; for (int i=0; i<=siz; ++i) cout<<g[i]<<' '; cout<<endl;
		for (int i=0; i<=it.fir.size(); ++i) h[i]=0;
		for (int s=0; s<lim; ++s) md(h[__builtin_popcount(s)], f[now][s]);
		// cout<<"h: "; for (int i=0; i<=it.fir.size(); ++i) cout<<h[i]<<' '; cout<<endl;
	}
	void dfs2(int u) {
		vis[u]=1;
		for (auto v:to[u]) if (!vis[v.fir]) {
			intr[u][v.fir]=intr[v.fir][u]=1;
			dfs2(v.fir);
			// cout<<"link: "<<u<<' '<<v.fir<<' '<<v.sec<<endl;
		}
	}
	void dfs3(int u, int fa) {
		// cout<<"dfs3: "<<u<<' '<<fa<<endl;
		sub[u]=1;
		dp[u][0][0]=!vis[u]; dp[u][1][0]=vis[u];
		for (auto& v:to[u]) if (v.fir!=fa && intr[u][v.fir]) {
			dfs3(v.fir, u);
			// cout<<"merge: "<<u<<' '<<v.fir<<endl;
			// cout<<"dp0: "; for (int i=0; i<=sub[u]; ++i) cout<<dp[u][0][i]<<' '; cout<<endl;
			// cout<<"dp1: "; for (int i=0; i<=sub[u]; ++i) cout<<dp[u][1][i]<<' '; cout<<endl;
			for (int i=0; i<=sub[u]+sub[v.fir]; ++i) tem[0][i]=tem[1][i]=0;
			for (int i=0; i<=sub[u]; ++i) {
				for (int j=0; j<=sub[v.fir]; ++j) {
					tem[0][i+j]=(tem[0][i+j]+dp[u][0][i]*(dp[v.fir][0][j]+dp[v.fir][1][j]))%mod;
					tem[1][i+j]=(tem[1][i+j]+dp[u][1][i]*(dp[v.fir][0][j]+dp[v.fir][1][j]))%mod;
					tem[1][i+j+1]=(tem[1][i+j+1]+dp[u][0][i]*dp[v.fir][0][j]%mod*v.sec)%mod;
				}
			}
			sub[u]+=sub[v.fir];
			for (int i=0; i<=sub[u]; ++i) dp[u][0][i]=tem[0][i], dp[u][1][i]=tem[1][i];
			// cout<<"tem0: "; for (int i=0; i<=sub[u]; ++i) cout<<tem[0][i]<<' '; cout<<endl;
			// cout<<"tem1: "; for (int i=0; i<=sub[u]; ++i) cout<<tem[1][i]<<' '; cout<<endl;
		}
		// cout<<"dp0: "; for (int i=0; i<=sub[u]; ++i) cout<<dp[u][0][i]<<' '; cout<<endl;
		// cout<<"dp1: "; for (int i=0; i<=sub[u]; ++i) cout<<dp[u][1][i]<<' '; cout<<endl;
		// cout<<"return "<<u<<endl;
	}
	void solve2(pair<vector<int>, vector<int>>& it, int m) {
		int n=it.fir.size()+it.sec.size();
		for (auto& t:it.fir) vis[t]=0;
		for (auto& t:it.sec) vis[t]=0;
		dfs2(it.fir[0]);
		vector<pair<int, pair<int, int>>> sta;
		for (auto& u:it.fir)
			for (auto& v:to[u]) if (!intr[u][v.fir])
				sta.pb({u, v});
		// cout<<"sta: "; for (auto it:sta) cout<<"("<<it.fir<<','<<it.sec.fir<<','<<it.sec.sec<<") "; cout<<endl;
		int lim=1<<sta.size();
		// cout<<"lim: "<<lim<<endl;
		for (int i=0; i<=it.fir.size(); ++i) h[i]=0;
		for (int s=0; s<lim; ++s) {
			for (auto& u:it.fir) {
				vis[u]=0;
				for (int i=0; i<=n; ++i) dp[u][0][i]=dp[u][1][i]=0;
			}
			for (auto& u:it.sec) {
				vis[u]=0;
				for (int i=0; i<=n; ++i) dp[u][0][i]=dp[u][1][i]=0;
			}
			ll val=1;
			for (int i=0; i<sta.size(); ++i) if (s&(1<<i)) {
				if (vis[sta[i].fir]||vis[sta[i].sec.fir]) goto jump;
				// cout<<"add edge: "<<sta[i].fir<<' '<<sta[i].sec.fir<<' '<<sta[i].sec.sec<<endl;
				vis[sta[i].fir]=vis[sta[i].sec.fir]=1;
				val=val*sta[i].sec.sec%mod;
			}
			// cout<<"go dfs"<<endl;
			dfs3(it.fir[0], 0);
			for (int i=0; i<=sub[it.fir[0]]; ++i) h[i+__builtin_popcount(s)]=(h[i+__builtin_popcount(s)]+val*(dp[it.fir[0]][0][i]+dp[it.fir[0]][1][i]))%mod;
			jump: ;
		}
		// cout<<"h: "; for (int i=0; i<=it.fir.size(); ++i) cout<<h[i]<<' '; cout<<endl;
	}
	void solve() {
		for (int i=1; i<=xsiz; ++i) id1[i]=++tot;
		for (int i=1; i<=ysiz; ++i) id2[i]=++tot;
		for (int i=1; i<=k; ++i) {
			to[id1[x[i]]].pb({id2[y[i]], w[i]-1});
			to[id2[y[i]]].pb({id1[x[i]], w[i]-1});
		}
		for (int i=1; i<=xsiz; ++i) if (to[id1[i]].size() && !vis[id1[i]]) {
			pair<vector<int>, vector<int>> tem;
			dfs(id1[i], 0, tem);
			sta.pb(tem);
		}
		g[0]=1;
		for (auto& it:sta) {
			// cout<<"it.fir: "; for (auto t:it.fir) cout<<t<<' '; cout<<endl;
			// cout<<"it.sec: "; for (auto t:it.sec) cout<<t<<' '; cout<<endl;
			if (it.fir.size()>it.sec.size()) swap(it.fir, it.sec);
			int m=0;
			for (auto& t:it.fir) m+=to[t].size();
			if (it.fir.size()+it.sec.size()<0.666*m) solve1(it);
			else solve2(it, m);
			for (int i=0; i<=siz+it.fir.size(); ++i) t[i]=0;
			for (int i=0; i<=siz; ++i)
				for (int j=0; j<=it.fir.size(); ++j)
					t[i+j]=(t[i+j]+g[i]*h[j])%mod; //, cout<<"add: "<<i+j<<' '<<g[i]<<' '<<h[j]<<endl;
			siz+=it.fir.size();
			for (int i=0; i<=siz; ++i) g[i]=t[i];
		}
		// cout<<"g: "; for (int i=0; i<=siz; ++i) cout<<g[i]<<' '; cout<<endl;
		for (int i=0; i<=siz; ++i) ans=(ans+fac[n-i]*g[i])%mod;
		printf("%lld\n", (ans%mod+mod)%mod);
	}
}

signed main()
{
	// freopen("field.in", "r", stdin);
	// freopen("field.out", "w", stdout);

	n=read(); k=read();
	for (int i=1; i<=k; ++i) x[i]=read(), y[i]=read(), w[i]=read();
	fac[0]=fac[1]=1;
	for (int i=2; i<=n; ++i) fac[i]=fac[i-1]*i%mod;
	for (int i=1; i<=k; ++i) {
		unix[++xsiz]=x[i];
		uniy[++ysiz]=y[i];
	}
	sort(unix+1, unix+xsiz+1);
	sort(uniy+1, uniy+ysiz+1);	
	xsiz=unique(unix+1, unix+xsiz+1)-unix-1;
	ysiz=unique(uniy+1, uniy+ysiz+1)-uniy-1;
	for (int i=1; i<=k; ++i) {
		x[i]=lower_bound(unix+1, unix+xsiz+1, x[i])-unix;
		y[i]=lower_bound(uniy+1, uniy+ysiz+1, y[i])-uniy;
	}
	task2::solve();

	return 0;
}
posted @ 2022-08-01 22:08  Administrator-09  阅读(6)  评论(0编辑  收藏  举报