CF 1842 H
给自己的博客引流:3.15 解除密码 这个是这篇中最认真写的题。
妙妙题!!!太牛了。
首先,
考虑一个白点和一个黑点怎么加起来
如果我们不考虑时间复杂度,那么我们想求出的是:
-
把
个点黑白染色。 -
这种染色方案对应的图要是无环的,即有拓扑序。拓扑序是按照
的从小到大排序。
这个比较难求,我们可以反之求一个拓扑序,它对应的可行的黑白染色个数,设为
设
-
如果
,则 。也就是说,固定 对应的时候, 的已经在他前面了。 -
如果
,则 。也就是说,固定 对应的时候, 的已经在他前面了。这是因为, 的 这个值更小。
那么,就很好转移了。具体来说,对于所有
-
如果所有关于
的 的限制的另一端都确定了, 就可以是黑色。 -
如果所有关于
的 的限制的另一端都确定了, 就可以是白色。
时间复杂度
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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?