场上数据很水,比较暴力的做法都可以过90分以上,下面说几个做法。

1. 暴力枚举所有最大独立集,对每个独立集分别DP。复杂度玄学,但是由于最大独立集并不多,所以可以拿90.

2. dp[S][k]表示考虑到排列的第k位,当前独立集为S的方案数,枚举第k+1位,根据是否与S相连转移到dp[S][k+1]或dp[S | a[k+1]][k+1]。$O(n^22^n)$

3. dp[S]表示排列的状态为S时的正确率,mx[S]表示排列状态为S时能得到的最大独立集大小,考虑转移,枚举排列里最后一个在独立集中的点i∈S,从S中删去所有与i相连的点得到S',若mx[S]<mx[S']+1则更新mx[S],dp[S]清零,否则累加。注意到每个排列都是等概率出现的,所以最后直接除以|S|即可。 $O(n2^n)$

方法一:

 #include<cstdio>
#include<cstring>
#include<algorithm>
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
#define ll long long
using namespace std; const int N=<<,mod=;
ll n,m,x,y,s[],p[],f[N][],cnt,mx,v[N],num[N],t[N],ans,o[N]; int main(){
freopen("walk.in","r",stdin);
freopen("walk.out","w",stdout);
scanf("%lld%lld",&n,&m);
p[]=; rep(i,,n) p[i]=p[i-]<<;
rep(i,,m) scanf("%lld%lld",&x,&y),s[x]|=p[y],s[y]|=p[x];
cnt=(<<n)-; f[][]=;
rep(i,,cnt){
ll tmp=; v[i]=;
rep(j,,n) if ((i&p[j])&&(s[j]&i)) v[i]=;
if (v[i]){
rep(j,,n) if (i&p[j]) tmp++,t[i]|=s[j];
num[i]=tmp; mx=max(mx,tmp);
tmp=;
rep(j,,n) if (t[i]&p[j]) tmp++;
o[i]=tmp;
}
}
rep(i,,cnt) if (v[i])
rep(j,,o[i]){
if (j!=o[i]) f[i][j+]=(f[i][j+]+f[i][j]*(o[i]-j))%mod;
rep(k,,n) if (!(i&p[k])&&!(p[k]&t[i])) f[i|p[k]][j]=(f[i|p[k]][j]+f[i][j])%mod;
if (num[i]==mx && j==o[i]) ans=(ans+f[i][j])%mod;
}
printf("%lld\n",ans);
return ;
}

方法二:

 #include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
#define P 998244353
#define N 21
#define t (1<<n)
int n,m;
long long ans=;
bool flag[<<(N-)];
int s[<<(N-)],w[N],v[<<(N-)],cnt[<<(N-)],tot[<<(N-)],f[][<<(N-)],maximum=;
int main()
{
freopen("walk.in","r",stdin);
freopen("walk.out","w",stdout);
n=read(),m=read();
for (int i=;i<=n;i++) w[i]=<<(i-),s[w[i]]=w[i];
for (int i=;i<=m;i++)
{
int x=read(),y=read();
s[w[x]]|=w[y],s[w[y]]|=w[x];
}
flag[]=;
for (int i=;i<t;i++)
if (flag[i])
for (int j=;j<=n;j++)
if (!(w[j]&s[i]))
{
flag[i|w[j]]=,s[i|w[j]]=s[i]|s[w[j]],cnt[i|w[j]]=cnt[i]+;
if (cnt[i]>=maximum) maximum=cnt[i|w[j]];
}
for (int i=;i<t;i++)
{
s[i]=(~s[i])&(t-);
register int k=s[i];
while (k) k^=k&-k,tot[i]++;
v[i]=i&-i;
}
f[][]=;
for (register int i=;i<n;i++)
for (register int j=;j<t;j++)
if (f[i][j])
{
for (register int k=s[j];k;k^=v[k])
f[i+][j|v[k]]=(f[i+][j|v[k]]+f[i][j])%P;
f[i+][j]=(1ll*f[i][j]*(n-i-tot[j])+f[i+][j])%P;
}
for (int i=;i<t;i++) if (cnt[i]==maximum) ans=(ans+f[n][i])%P;
cout<<ans;
fclose(stdin);fclose(stdout);
return ;
}

方法三:

 #include<cstdio>
#include<cstring>
#include<algorithm>
#define rep(i,l,r) for (int i=l; i<=r; i++)
typedef long long ll;
using namespace std; const int N=,mod=;
int n,m,x,y,inv[N],f[N],mx[<<N],F[<<N]; int main(){
scanf("%d%d",&n,&m);
rep(i,,m) scanf("%d%d",&x,&y),x--,y--,f[x]|=<<y,f[y]|=<<x;
inv[]=; f[]|=; F[]=;
rep(i,,n) f[i-]|=(<<(i-)),inv[i]=1ll*inv[mod%i]*(mod-mod/i)%mod;
for (int i=; i<(<<n); i++){
int tot=;
for (int j=; j<n; j++) if (i&(<<j)){
int s=i&(~f[j]);
if (mx[i]<mx[s]+) mx[i]=mx[s]+,F[i]=;
if (mx[i]==mx[s]+) F[i]=(F[i]+F[s])%mod;
tot++;
}
F[i]=1ll*F[i]*inv[tot]%mod;
}
printf("%d\n",F[(<<n)-]);
return ;
}

[LOJ#2540][PKUWC2018]随机算法(概率DP)的更多相关文章

  1. LOJ #2540. 「PKUWC 2018」随机算法(概率dp)

    题意 LOJ #2540. 「PKUWC 2018」随机算法 题解 朴素的就是 \(O(n3^n)\) dp 写了一下有 \(50pts\) ... 大概就是每个点有三个状态 , 考虑了但不在独立集中 ...

  2. 【洛谷5492】[PKUWC2018] 随机算法(状压DP)

    点此看题面 大致题意: 用随机算法求一张图的最大独立集:每次随机一个排列,从前到后枚举排列中的点,如果当前点加入点集中依然是独立集,就将当前点加入点集中,最终得到的点集就是最大独立集.求这个随机算法的 ...

  3. [PKUWC2018]随机算法

    题意:https://loj.ac/problem/2540 给定一个图(n<=20),定义一个求最大独立集的随机化算法 产生一个排列,依次加入,能加入就加入 求得到最大独立集的概率 loj25 ...

  4. [LOJ2540] [PKUWC2018] 随机算法

    题目链接 LOJ:https://loj.ac/problem/2540 Solution 写的时候脑子不太清醒码了好长然后时间\(LOJ\)垫底... 反正随便状压\(dp\)一下就好了,设\(f[ ...

  5. LOJ #2542 [PKUWC2018]随机游走 (概率期望、组合数学、子集和变换、Min-Max容斥)

    很好很有趣很神仙的题! 题目链接: https://loj.ac/problem/2542 题意: 请自行阅读 题解首先我们显然要求的是几个随机变量的最大值的期望(不是期望的最大值),然后这玩意很难求 ...

  6. LOJ2540 PKUWC2018 随机算法 状压DP

    传送门 两种$DP$: ①$f_{i,j}$表示前$i$次选择,最大独立集为$j$时达到最大独立集的方案总数,转移:$a.f_{i,j}+=f_{i+1,j+2^k}$(保证$k$加入后符合条件):$ ...

  7. LOJ2540 [PKUWC2018] 随机算法 【状压DP】

    题目分析: 听说这题考场上能被$ O(4^n) $的暴力水过,难不成出题人是毕姥爷? 首先思考一个显而易见的$ O(n^2*2^n) $的暴力DP.一般的DP都是考虑最近的加入了哪个点,然后删除后递归 ...

  8. [BZOJ5006][LOJ#2290][THUWC2017]随机二分图(概率+状压DP)

    https://loj.ac/problem/2290 题解:https://blog.csdn.net/Vectorxj/article/details/78905660 不是很好理解,对于边(x1 ...

  9. LG5492 [PKUWC2018]随机算法

    题意 有一种贪心求最大独立集的算法: 随机一个排列 按顺序加入独立集,如果一个点能加入,就加入\({S}\) 给出一张图,问得出正确答案的概率. \(n \leq 20\) 传送门 思路 用 \(dp ...

随机推荐

  1. 防恶意解析,禁止用IP访问网站的Apache设置

    一般来说,网站可以用域名和IP来访问.你的网站可以通过IP直接访问,本来这没什么问题,但是会有些隐患: 由于搜索引擎也会收录你的IP地址的页面,所以同一个页面搜索引擎会重复收录,造成页面的权重不如单个 ...

  2. 第九届蓝桥杯C/C++B组题解附代码

    1.标题:第几天 2000年的1月1日,是那一年的第1天.那么,2000年的5月4日,是那一年的第几天? 125天 打开日历就ok 2. 标题:明码 汉字的字形存在于字库中,即便在今天,16点阵的字库 ...

  3. 团队代码中Bug太多怎么办?怎样稳步提高团队的代码质量

    最近负责的Android APP项目,由于团队成员变动.界面改版导致代码大幅修改等原因,产品发布后屡屡出现BUG导致的程序崩溃. 经过对异常统计和代码走读,BUG主要集中在空指针引起的NullPoin ...

  4. BAT定期删除N天前的文件

    1.直接看脚本在win2008测试可用 ::clean logs @echo off title clean up logs ::delete logs FORFILES /P /C "cm ...

  5. Spring学习--HelloWorld

    Spring: Spring 是一个开源框架. Spring 是为简化企业级应用开发而生,使用 Spring 可以使简单的 JavaBean 实现以前只有 EJB 才能实现的功能. Spring 是一 ...

  6. javaScript中的this关键字解析

    this是JavaScript中的关键字之一,在编写程序的时候经常会用到,正确的理解和使用关键字this尤为重要.接下来,笔者就从作用域的角度粗谈下自己对this关键字的理解,希望能给到大家一些启示, ...

  7. PHP文件操作函数二

    PHP部分文件访问函数总结: 1.filetype("文件路径")  //可以输出相关文件类型,返回之为:dir/file... 2.stat("文件名") / ...

  8. 「6月雅礼集训 2017 Day2」A

    [题目大意] 给出一棵树,求有多少对点(u,v)满足其路径上不存在两个点a,b满足(a,b)=1 n<=10^5 [题解] 考虑找出所有不符合的点对,共有n*ln(n)对,他们要么是祖先-> ...

  9. bzoj 2435 BFS

    我们可以先将无根树变成有根树,随便选一个点当根就行了,我们选1,bfs求出来每个点 的size值,代表以它为根节点的子树中有多少个节点,(dfs可能会爆栈),然后再对于每一条 边算就好了 我tle了, ...

  10. Python爬虫学习 - day1 - 爬取图片

    利用Python完成简单的图片爬取 最近学习到了爬虫,瞬时觉得很高大上,想取什么就取什么,感觉要上天.这里分享一个简单的爬取汽车之家文章列表的图片教程,供大家学习. 需要的知识点储备 本次爬虫脚本依赖 ...