[LOJ#2540][PKUWC2018]随机算法(概率DP)
场上数据很水,比较暴力的做法都可以过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)的更多相关文章
- LOJ #2540. 「PKUWC 2018」随机算法(概率dp)
题意 LOJ #2540. 「PKUWC 2018」随机算法 题解 朴素的就是 \(O(n3^n)\) dp 写了一下有 \(50pts\) ... 大概就是每个点有三个状态 , 考虑了但不在独立集中 ...
- 【洛谷5492】[PKUWC2018] 随机算法(状压DP)
点此看题面 大致题意: 用随机算法求一张图的最大独立集:每次随机一个排列,从前到后枚举排列中的点,如果当前点加入点集中依然是独立集,就将当前点加入点集中,最终得到的点集就是最大独立集.求这个随机算法的 ...
- [PKUWC2018]随机算法
题意:https://loj.ac/problem/2540 给定一个图(n<=20),定义一个求最大独立集的随机化算法 产生一个排列,依次加入,能加入就加入 求得到最大独立集的概率 loj25 ...
- [LOJ2540] [PKUWC2018] 随机算法
题目链接 LOJ:https://loj.ac/problem/2540 Solution 写的时候脑子不太清醒码了好长然后时间\(LOJ\)垫底... 反正随便状压\(dp\)一下就好了,设\(f[ ...
- LOJ #2542 [PKUWC2018]随机游走 (概率期望、组合数学、子集和变换、Min-Max容斥)
很好很有趣很神仙的题! 题目链接: https://loj.ac/problem/2542 题意: 请自行阅读 题解首先我们显然要求的是几个随机变量的最大值的期望(不是期望的最大值),然后这玩意很难求 ...
- LOJ2540 PKUWC2018 随机算法 状压DP
传送门 两种$DP$: ①$f_{i,j}$表示前$i$次选择,最大独立集为$j$时达到最大独立集的方案总数,转移:$a.f_{i,j}+=f_{i+1,j+2^k}$(保证$k$加入后符合条件):$ ...
- LOJ2540 [PKUWC2018] 随机算法 【状压DP】
题目分析: 听说这题考场上能被$ O(4^n) $的暴力水过,难不成出题人是毕姥爷? 首先思考一个显而易见的$ O(n^2*2^n) $的暴力DP.一般的DP都是考虑最近的加入了哪个点,然后删除后递归 ...
- [BZOJ5006][LOJ#2290][THUWC2017]随机二分图(概率+状压DP)
https://loj.ac/problem/2290 题解:https://blog.csdn.net/Vectorxj/article/details/78905660 不是很好理解,对于边(x1 ...
- LG5492 [PKUWC2018]随机算法
题意 有一种贪心求最大独立集的算法: 随机一个排列 按顺序加入独立集,如果一个点能加入,就加入\({S}\) 给出一张图,问得出正确答案的概率. \(n \leq 20\) 传送门 思路 用 \(dp ...
随机推荐
- 用原生JavaScript做个简单的回到顶部
很多网页在下方都会放置一个“返回顶部”按钮,尤其是页面底部没有导航的网页,这样可以帮助访客重新找到导航或者重温一遍广告(想得真美).随着近几年来 JavaScript 的应用日渐广泛,滑动效果无处不在 ...
- missing blocks错误
Datanode的日志中看到: 10/12/14 20:10:31 INFO hdfs.DFSClient: Could not obtain block blk_XXXXXXXXXXXXXXXXXX ...
- fieldset——一个不常用的HTML标签
fieldset 标签 -- 对表单进行分组 在form表单中,我们可以对form中的信息进行分组归类,如注册表单的form,我们可以将注册信息分组成 基本信息(一般为必填) 详细信息(一般为可选) ...
- es6+最佳入门实践(8)
8.Promise 8.1.什么是异步? 要理解异步,首先,从同步代码开始说 alert(1) alert(2) 像上面的代码,执行顺序是从上到下,先后弹出1和2,这种代码叫做同步代码 alert(0 ...
- MyEclipse快捷键大全(转)1
Ctrl+1 快速修复(最经典的快捷键,就不用多说了) Ctrl+D: 删除当前行 Ctrl+Alt+↓ 复制当前行到下一行(复制增加) Ctrl+Alt+↑ 复制当前行到上一行(复制增加) Alt+ ...
- mavne问题解决---Dynamic Web Module 2.3 or newer
一:前沿 maven问题的bug,其实是很烦人的,因为每次都是很纠结的去改这个bug,特别的烦人,这个bug也是使得我纠结了好久的,那个星期五自己搞了几个小时都没有解决下,之后星期一来百度Google ...
- sql数据库的链接方式
今天看见了一个数据库的链接方法,给转载了,记得我刚刚学DAO的时候老是要记载这些东西,所以就上博客园上面看了看,就转过来了... MySQL: String Driver="com.mysq ...
- The 2017 ACM-ICPC Asia East Continent League Final记录
首先感谢tyz学弟的麻麻-给我们弄到了名额- 然后就开始了ACM ECLFinal的玩耍,A*仙人掌可是立了flag要好好打的- 试机赛好像就全是GCJ kickstart的原题,然后AK了但是由于一 ...
- php windows rename 中文出错
php windows rename 中文出错 rename()函数可以重命名文件.目录等,但是要注意目的地和起始地址的编码. 比如:我的PHP文件编码是UTF-8,但是在WINDOW系统中中文默认编 ...
- [object-c 2.0 程序设计]object-c file handle (二)
// // main.m // cmdTry // // Created by Calos Chen on 2017/8/21. // Copyright © 2017年 Calos Chen. Al ...