C/C++教程

[PKUWC2018] 随机算法

本文主要是介绍[PKUWC2018] 随机算法,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

\(\text{Problem}:\)[PKUWC2018] 随机算法

\(\text{Solution}:\)

发现 \(n\) 很小,可以考虑状压 \(dp\)。设 \(f_{S}\) 表示得到集合 \(S\) 最大独立集的概率,\(g_{S}\) 表示集合 \(S\) 最大独立集的大小。

首先预处理 \(g\),枚举 \(S\) 中的元素 \(x\) 并删掉集合 \(S\) 内与 \(x\) 有连边的所有点,得到集合 \(T\),有转移:

\[g_{S}=\max\{g_{T}+1\} \]

考虑 \(f\) 的转移,只能从满足 \(g_{T}+1=g_{S}\) 的 \(T\) 转移到 \(S\)。考虑最后一个点的加入是随机的,故有转移:

\[f_{S}=\frac{1}{\lvert S\rvert}\sum\limits_{g_{T}+1=g_{S}}f_{T} \]

另一种推导方式是考虑 \(S\rightarrow S\cup T\)(\(T\) 是与加入的 \(i\) 相邻的点集,也包括 \(i\)),此时钦定 \(i\) 被第一个选中,剩下不在 \(S\) 中的元素随意排列的贡献为 \(A_{n-\lvert S\rvert-1}^{T\oplus (T\cap S)-1}\) 。最后除以 \(n!\) 即可。

两种做法的时间复杂度均为 \(O(2^{n}n)\),可以通过。

\(\text{Code}:\)

#include <bits/stdc++.h>
#pragma GCC optimize(3)
//#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
#define vi vector<int>
#define vpi vector<pair<int,int>>
using namespace std; const int N=20, Mod=998244353;
inline int read()
{
	int s=0, w=1; ri char ch=getchar();
	while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
	while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar();
	return s*w;
}
int n,m,up,to[N],iiv[N+5],cnt[(1<<N)+5],f[(1<<N)+5],g[(1<<N)+5];
inline int ksc(int x,int p) { int res=1; for(;p;p>>=1, x=1ll*x*x%Mod) if(p&1) res=1ll*res*x%Mod; return res; }
signed main()
{
	n=read(), m=read();
	iiv[1]=1;
	for(ri int i=2;i<=N;i++) iiv[i]=1ll*(Mod-Mod/i)*iiv[Mod%i]%Mod;
	for(ri int i=1;i<=m;i++)
	{
		int u,v;
		u=read(), v=read();
		u--, v--;
		to[u]|=(1<<v), to[v]|=(1<<u);
	}
	for(ri int i=0;i<n;i++) to[i]|=(1<<i);
	up=(1<<n);
	for(ri int i=1;i<up;i++)
	{
		for(ri int j=0;j<n;j++)
		if((i>>j)&1) g[i]=max(g[i],g[i&(to[j]^(up-1))]+1);
	}
	f[0]=1;
	for(ri int i=1;i<up;i++) cnt[i]=cnt[i>>1]+(i&1);
	for(ri int i=1;i<up;i++)
	{
		for(ri int j=0;j<n;j++)
		if((i>>j)&1 && g[i]==g[i&(to[j]^(up-1))]+1)
		f[i]=(f[i]+f[i&(to[j]^(up-1))])%Mod;
		f[i]=1ll*f[i]*iiv[cnt[i]]%Mod;
	}
	printf("%d\n",f[up-1]);
	return 0;
}
这篇关于[PKUWC2018] 随机算法的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!