CF 1842 H

给自己的博客引流:3.15 解除密码 这个是这篇中最认真写的题。

妙妙题!!!太牛了。

首先,xi[0,1],可以有两种:xi<0.5,xi0.5。因为在 [0,1] 中抽出 0.5 的几率为 0,就可以分成 xi<0.5,xi>0.5。如果这样分,那么 xi,xj<0.5xi+xj1xi,xj>0.5xi+xj1。因此我们只需要考虑 xi<0.5,xj>0.5 或者反过来的情况。为了方便起见,设 <0.5 为白色的,>0.5 为黑色的,默认 xi 白色,xj 黑色。

考虑一个白点和一个黑点怎么加起来 1。几个解释是,黑色的到 1 的距离比白色的值大,即 1xj>xi。如果加起来 1,则 1xj<xi。(如果 xi>xj,则反过来)所以,我们可以求出 min(xi,1xi)min(xj,1xj) 的大小关系。我们可以小的向大的连边,形成一个图。

如果我们不考虑时间复杂度,那么我们想求出的是:

  • n 个点黑白染色。

  • 这种染色方案对应的图要是无环的,即有拓扑序。拓扑序是按照 min(xi,1xi) 的从小到大排序。

这个比较难求,我们可以反之求一个拓扑序,它对应的可行的黑白染色个数,设为 cnt。答案就是 cnt2n×n!

dpmsk 为已经固定好了 msk 里面包含的数(作为 min(xi,1xi) 最小的 popcnt(msk) 个)的黑白染色方案数。怎么转移呢?我们还可以发现两个性质:

  • 如果 xa+xb1,则 min(xa,xb)<0.5。也就是说,固定 max(xa,xb) 对应的时候,min 的已经在他前面了。

  • 如果 xa+xb1,则 max(xa,xb)>0.5。也就是说,固定 min(xa,xb) 对应的时候,max 的已经在他前面了。这是因为,maxmin(xi,1xi) 这个值更小。

那么,就很好转移了。具体来说,对于所有 jmsk

  • 如果所有关于 j1 的限制的另一端都确定了,j 就可以是黑色。

  • 如果所有关于 j1 的限制的另一端都确定了,j 就可以是白色。

时间复杂度 O(2nn)

Code
#include <bits/stdc++.h>

using namespace std;

using ll = long long;

const ll mod = 998244353;

ll pw(ll x,ll y=mod-2){
	ll res=1;
	while (y){
		if (y&1){
			res=res*x%mod;
		}
		x=x*x%mod;
		y>>=1;
	}
	return res;
}

ll msk[2][20],dp[1<<20];

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);

	int n,m;
	cin>>n>>m;
	ll fac=1;
	for (ll i=1; i<=n; i++){
		fac=fac*i%mod;
	}
	ll div=pw(2,n)*fac%mod;
	for (int i=1; i<=m; i++){
		ll t,a,b;
		cin>>t>>a>>b;
		a--;
		b--;
		msk[t][a]|=1<<b;
		msk[t][b]|=1<<a;
	}
	dp[0]=1;
	for (int i=0; i<(1<<n); i++){
		for (int j=0; j<n; j++){
			if (!(i>>j&1)){
				if ((msk[0][j]|i)==i){
					(dp[i^(1<<j)]+=dp[i])%=mod;
				}
				if ((msk[1][j]|i)==i){
					(dp[i^(1<<j)]+=dp[i])%=mod;
				}
			}
		}
	}
	cout<<dp[(1<<n)-1]*pw(div)%mod<<"\n";
	return 0;
}
posted @   SFlyer  阅读(15)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示