bzoj 5006(洛谷 4547) [THUWC2017]Bipartite 随机二分图——期望DP
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=5006
https://www.luogu.org/problemnew/show/P4547
算一种可行方案,只要确定出 n 条边即可;概率就是这 n 条边存在的概率,其他边视作无要求,概率贡献都是1;这样的话,一种方案对答案的贡献就是其概率。
考虑把第二组边和第三组边分成概率分别为 1/2 的两条独立的边。对于第二组边再加一条能把4个点都连起来的 1/4 的边,对于第三组边再加一条能把4个点都连起来的 -1/4 的边。
因为算一个方案的概率的时候只看选中的边的概率乘积,所以上述方案可以让概率计算正确。
可以设 dp[ s0 ][ s1 ] 表示左部的点集 s0 和右部的点集 s1 匹配的期望方案数。然后记忆化搜索。(也可以刷表,还会快,但不太会写)
为了避免方案数因为加边顺序而算重,可以规定一个顺序,比如转移到 (s0,s1) 的状态 (d0,d1) 的 d0 一定不含 s0 的 lowbit 之类的。
于是枚举 d0 , d1 ,但会TLE。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define mkp make_pair
#define pii pair<int,int>
#define ll long long
using namespace std;
int rdn()
{
int ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return fx?ret:-ret;
}
const int N=,M=,mod=1e9+;
int n,m,bin[N],dy[(<<)+],iv2,iv4; bool s[N][N];
map<pii,int> s2,mp;
int pw(int x,int k)
{int ret=;while(k){if(k&)ret=(ll)ret*x%mod;x=(ll)x*x%mod;k>>=;}return ret;}
void upd(int &x){x>=mod?x-=mod:;}
int dfs(int s0,int s1)
{
pii S=mkp(s0,s1);if(mp.count(S))return mp[S];
int lbt=(s0&-s0);
int x=dy[lbt],y,d0=s0^(lbt),p0=s1,d1;
while(p0)//every bit of s1
{
lbt=(p0&-p0);
y=dy[lbt]; d1=s1^lbt; p0^=lbt;
if(s[x][y])
mp[S]=(mp[S]+(ll)iv2*dfs(d0,d1))%mod;
}
p0=d0; x=(s0&-s0);
while(p0)//every bit of (s0-lowbit)
{
lbt=(p0&-p0); d0=(x|lbt); p0^=lbt;//d0:two bits of s0
int p1=s1;//every bit of s1
while(p1)
{
lbt=(p1&-p1); y=lbt; p1^=lbt;
int p2=p1;//d1:every bit of p1
while(p2)
{
lbt=(p2&-p2); d1=(y|lbt); p2^=lbt;
pii d=mkp(d0,d1);
if(s2.count(d))
mp[S]=(mp[S]+(ll)iv4*dfs(s0^d0,s1^d1)*s2[d])%mod+mod,upd(mp[S]);
}
}
}
return mp[S];
}
int main()
{
int m,t,x1,y1,x2,y2;
n=rdn();m=rdn();
bin[]=;dy[]=;for(int i=;i<=n;i++)bin[i]=bin[i-]<<,dy[bin[i]]=i;
iv2=pw(,mod-); iv4=pw(,mod-); mp[mkp(,)]=bin[n];
for(int i=;i<=m;i++)
{
t=rdn();x1=rdn()-;y1=rdn()-;
if(t)x2=rdn()-,y2=rdn()-;
s[x1][y1]=; if(!t)continue;
s[x2][y2]=;
s2[mkp(bin[x1]|bin[x2],bin[y1]|bin[y2])]=(t==?:-);
}
printf("%d\n",dfs(bin[n]-,bin[n]-));
return ;
}
于是改成枚举每条边,并且把两个点集压进一个数而不是两个数里。但还是TLE。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define mkp make_pair
#define pii pair<int,int>
#define ll long long
using namespace std;
int rdn()
{
int ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return fx?ret:-ret;
}
const int N=,M=,mod=1e9+;
int n,m,bin[N],iv2,iv4;
struct Ed{
int x,y,w;
Ed(int x=,int y=,int w=):x(x),y(y),w(w) {}
}ed[M];
map<pii,int> mp;
int pw(int x,int k)
{int ret=;while(k){if(k&)ret=(ll)ret*x%mod;x=(ll)x*x%mod;k>>=;}return ret;}
void upd(int &x){x>=mod?x-=mod:;}
int dfs(int s0,int s1)
{
pii S=mkp(s0,s1);if(mp.count(S))return mp[S];
int lbt=(s0&-s0);
for(int i=;i<=m;i++)
if((ed[i].x|s0)==s0&&(ed[i].y|s1)==s1&&(ed[i].x&lbt))
mp[S]=(mp[S]+(ll)ed[i].w*dfs(s0^ed[i].x,s1^ed[i].y))%mod;
return mp[S];
}
int main()
{
int tp,t,x1,y1,x2,y2;
n=rdn();tp=rdn();
bin[]=;for(int i=;i<=n;i++)bin[i]=bin[i-]<<;
iv2=pw(,mod-); iv4=pw(,mod-); mp[mkp(,)]=bin[n];
for(int i=;i<=tp;i++)
{
t=rdn();x1=bin[rdn()-];y1=bin[rdn()-];
ed[++m]=Ed(x1,y1,iv2); if(!t)continue;
x2=bin[rdn()-];y2=bin[rdn()-];
ed[++m]=Ed(x2,y2,iv2);
if((x1&x2)||(y1&y2))continue;///
ed[++m]=Ed(x1|x2,y1|y2,t==?iv4:mod-iv4);
}
printf("%d\n",dfs(bin[n]-,bin[n]-));
return ;
}
主要是 map 的大小。在 mp[ s0 ] 里找有没有 s1 比在整个 (s0,s1) 里找有没有 (s0,s1) 快。
并且不要写很多 mp[ s0 ][ s1 ] ,可以用一个临时变量 ret 之类的代替。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define ll long long
using namespace std;
int rdn()
{
int ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return fx?ret:-ret;
}
const int N=,M=,mod=1e9+;
int n,m,bin[N<<],iv2,iv4,base;
struct Ed{
int s,w;
Ed(int s=,int w=):s(s),w(w) {}
}ed[M];
map<int,int> mp[(<<)+];
int pw(int x,int k)
{int ret=;while(k){if(k&)ret=(ll)ret*x%mod;x=(ll)x*x%mod;k>>=;}return ret;}
int dfs(int S)
{
int s0=S>>n,s1=S&base;
if(mp[s0].count(s1))return mp[s0][s1];
int ret=;
for(int i=;i<=m;i++)
if((ed[i].s|S)==S&&(ed[i].s<<)>S)
ret=(ret+(ll)ed[i].w*dfs(S^ed[i].s))%mod;
return mp[s0][s1]=ret;
}
int main()
{
int tp,t,s1,s2;
n=rdn();tp=rdn();
bin[]=;for(int i=,j=n<<;i<=j;i++)bin[i]=bin[i-]<<;
iv2=pw(,mod-); iv4=pw(,mod-); base=bin[n]-; mp[][]=bin[n];
for(int i=;i<=tp;i++)
{
t=rdn();s1=bin[rdn()-+n]|bin[rdn()-];
ed[++m]=Ed(s1,iv2); if(!t)continue;
s2=bin[rdn()-+n]|bin[rdn()-];
ed[++m]=Ed(s2,iv2);
if(s1&s2)continue;///
ed[++m]=Ed(s1|s2,t==?iv4:mod-iv4);
}
printf("%d\n",dfs(bin[n<<]-));
return ;
}
bzoj 5006(洛谷 4547) [THUWC2017]Bipartite 随机二分图——期望DP的更多相关文章
- bzoj5006: [THUWC2017 Bipartite]随机二分图
某人在玩一个非常神奇的游戏.这个游戏中有一个左右各 nnn 个点的二分图,图中的边会按照一定的规律随机出现. 为了描述这些规律,某人将这些边分到若干个组中.每条边或者不属于任何组 (这样的边一定不会出 ...
- 洛谷P3239 [HNOI2015]亚瑟王(期望dp)
传送门 stdcall大佬好强 期望的姿势不是很高……据大佬说期望有一个线性性质,也就是说可以把每一张牌的期望伤害算出来然后再加起来就是总的期望伤害 因为每一张牌只能用一次,我们设$dp[i]$表示第 ...
- 洛谷P1365 WJMZBMR打osu! / Easy——期望DP
题目:https://www.luogu.org/problemnew/show/P1365 平方和怎样递推? 其实就是 (x+1)^2 = x^2 + 2*x + 1: 所以我们要关注这里的 x — ...
- 洛谷 P3239 [HNOI2015]亚瑟王(期望+dp)
题面传送门 感觉是道挺好的题,可惜当时没写题解来着的? 根据期望的线性公式,我们求出每个卡牌被发动的概率 \(q_i\),然后 \[ans=\sum\limits_{i=1}^np_id_i \] 于 ...
- 洛谷 P5249 - [LnOI2019]加特林轮盘赌(期望 dp+高斯消元)
题面传送门 期望真 nm 有意思,所以蒟蒻又来颓期望辣 先特判掉 \(P_0=0\) 的情况,下面假设 \(P_0\ne 0\). 首先注意到我们每次将加特林对准一个人,如果这个人被毙掉了,那么相当于 ...
- [BZOJ 3039&洛谷P4147]玉蟾宫 题解(单调栈)
[BZOJ 3039&洛谷P4147]玉蟾宫 Description 有一天,小猫rainbow和freda来到了湘西张家界的天门山玉蟾宫,玉蟾宫宫主蓝兔盛情地款待了它们,并赐予它们一片土地. ...
- 【THUWC2017】随机二分图(动态规划)
[THUWC2017]随机二分图(动态规划) 题面 BZOJ 洛谷 题解 如果每天边的限制都是\(0.5\)的概率出现或者不出现的话,可以把边按照二分图左侧的点的编号排序,然后设\(f[i][S]\) ...
- bzoj 3680(洛谷1337) 吊打XXX——模拟退火
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3680 https://www.luogu.org/problemnew/show/P1337 ...
- bzoj 4816: 洛谷 P3704: [SDOI2017]数字表格
洛谷很早以前就写过了,今天交到bzoj发现TLE了. 检查了一下发现自己复杂度是错的. 题目传送门:洛谷P3704. 题意简述: 求 \(\prod_{i=1}^{N}\prod_{j=1}^{M}F ...
随机推荐
- Mysql日期转换函数、时间转换函数
Mysql日期转换函数.时间转换函数 一.MySQL 获得当前日期时间 函数 1,获得当前日期+时间(date + time)函数:now(): select now(); 结果: :: 2,获得当前 ...
- js 变量、函数提升 与js的预编译有关
参考网址:http://www.codesec.net/view/178491.html 先简单理解下作用域的概念,方便对变量与函数提升的概念的理解 function foo() { var x = ...
- HDU 3709 Balanced Number(数位DP)题解
思路: 之前想直接开左右两边的数结果爆内存... 枚举每次pivot的位置,然后数位DP,如果sum<0返回0,因为已经小于零说明已经到了pivot右边,继续dfs只会越来越小,且dp数组会炸 ...
- 【eclipse】Server Tomcat v9.0 Server at localhost failed to start.
Server Tomcat v9.0 Server at localhost failed to start. 的一个原因就是启动超时了.
- SpringBoot与Dubbo整合上篇
最近学习了一下dubbo,是阿里巴巴公司的一个开源服务框架.目前我们公司实现两个不同系统的之间通信,是采用了Oracle的OSB作为服务的管理(即企业服务总线的一种实现),服务提供方在OSB上注册业务 ...
- POJ 2762 Going from u to v or from v to u? (判断单连通)
http://poj.org/problem?id=2762 题意:给出有向图,判断任意两个点u和v,是否可以从u到v或者从v到u. 思路: 判断图是否是单连通的. 首先来一遍强连通缩点,重新建立新图 ...
- 递归--练习3--noi7592求最大公约数问题
递归--练习3--noi7592求最大公约数问题 一.心得 两个低级错误:1. ll setMax(ll &m,ll &n)中无引用,结果只传值,没传地址2. return f(n,m ...
- mysql--------命令来操作表
常用的通过mysql命令来更改表结构的一些sql语句,包括添加.删除.修改字段.调整字段顺序. 添加字段: alter table `user_movement_log` Add column Gat ...
- css强制html不换行 css强制英文单词断行 重拾丢失的
css强制html不换行 css强制英文单词断行 强制不换行 div{ white-space:nowrap; } 自动换行 div{ word-wrap: break-word; word-brea ...
- BZOJ1074 [SCOI2007]折纸origami
我们先看每个点可能从哪些点折过来的,2^10枚举对角线是否用到. 然后再模拟折法,查看每个点是否满足要求. 恩,计算几何比较恶心,还好前几天刚写过一道更恶心的计算几何,点类直接拷过来2333. /** ...