[BZOJ5287][HNOI2018]毒瘤(虚树DP)
暴力枚举非树边取值做DP可得75。
注意到每次枚举出一个容斥状态的时候,都要做大量重复操作。
建立虚树,预处理出虚树上两点间的转移系数。也可动态DP解决。
树上倍增、动态DP、虚树DP似乎是这种问题的三种通用解法。
代码不是特别长但极其难写,预处理过程中要考虑各种情况。水平不够只好抄代码。
#include<cstdio>
#include<algorithm>
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
#define For(i,x) for (int i=h[x],k; i; i=nxt[i])
using namespace std; const int N=,mod=;
bool mark[N],vis[N],ban[N][];
int n,m,u,v,tot,tim,ans,sz[N],du[N],dv[N],dfn[N],dp[N][],g[N][];
struct P{ int k0,k1; }K[N][]; P operator +(const P &a,const P &b){ return (P){(a.k0+b.k0)%mod,(a.k1+b.k1)%mod}; }
P operator *(const P &a,int x){ return (P){int(1ll*a.k0*x%mod),int(1ll*a.k1*x%mod)}; } struct Edge{
int cnt,h[N],to[N<<],nxt[N<<];
P val[][];
void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
void add(int u,int v,const P &a,const P &b){
to[++cnt]=v; val[cnt][]=a; val[cnt][]=b; nxt[cnt]=h[u]; h[u]=cnt;
} void dfs1(int x,int fa){
dfn[x]=++tim;
For(i,x) if ((k=to[i])!=fa){
if (!dfn[k]) dfs1(k,x),sz[x]+=sz[k];
else if (dfn[k]<dfn[x]) du[++tot]=x,dv[tot]=k,mark[x]=mark[k]=;
}
mark[x]|=(sz[x]>=); if (mark[x]) sz[x]=;
} void dfs3(int x){
dp[x][]=ban[x][] ? : g[x][];
dp[x][]=ban[x][] ? : g[x][];
For(i,x){
dfs3(k=to[i]);
dp[x][]=1ll*dp[x][]*(1ll*val[i][].k0*dp[k][]%mod+1ll*val[i][].k1*dp[k][]%mod)%mod;
dp[x][]=1ll*dp[x][]*(1ll*val[i][].k0*dp[k][]%mod+1ll*val[i][].k1*dp[k][]%mod)%mod;
}
}
}G1,G2; int dfs2(int x){
g[x][]=g[x][]=; vis[x]=; int t=;
for (int i=G1.h[x],k; i; i=G1.nxt[i]) if (!vis[k=G1.to[i]]){
int z=dfs2(k);
if (!z) g[x][]=1ll*g[x][]*(g[k][]+g[k][])%mod,g[x][]=1ll*g[x][]*g[k][]%mod;
else{
if (mark[x]) G2.add(x,z,K[k][]+K[k][],K[k][]);
else K[x][]=K[k][]+K[k][],K[x][]=K[k][],t=z;
}
}
if (mark[x]) K[x][]=(P){,},K[x][]=(P){,},t=x;
else K[x][]=K[x][]*g[x][],K[x][]=K[x][]*g[x][];
return t;
} int main(){
freopen("bzoj5287.in","r",stdin);
freopen("bzoj5287.out","w",stdout);
scanf("%d%d",&n,&m);
rep(i,,m) scanf("%d%d",&u,&v),G1.add(u,v),G1.add(v,u);
G1.dfs1(,); mark[]=; dfs2();
for (int S=; S<(<<tot); S++){
rep(i,,tot) if (S&(<<(i-))) ban[dv[i]][]=,ban[du[i]][]=; else ban[dv[i]][]=;
G2.dfs3(); ans=(ans+(dp[][]+dp[][])%mod)%mod;
rep(i,,tot) if (S&(<<(i-))) ban[dv[i]][]=,ban[du[i]][]=; else ban[dv[i]][]=;
}
printf("%d\n",ans);
return ;
}
[BZOJ5287][HNOI2018]毒瘤(虚树DP)的更多相关文章
- BZOJ.5287.[AHOI HNOI2018]毒瘤(虚树 树形DP)
BZOJ LOJ 洛谷 设\(f[i][0/1]\)表示到第\(i\)个点,不选/选这个点的方案数.对于一棵树,有:\[f[x][0]=\prod_{v\in son[x]}(f[v][0]+f[v] ...
- bzoj 3572世界树 虚树+dp
题目大意: 给一棵树,每次给出一些关键点,对于树上每个点,被离它最近的关键点(距离相同被标号最小的)控制 求每个关键点控制多少个点 分析: 虚树+dp dp过程如下: 第一次dp,递归求出每个点子树中 ...
- bzoj 2286 [Sdoi2011]消耗战 虚树+dp
题目大意:多次给出关键点,求切断边使所有关键点与1断开的最小费用 分析:每次造出虚树,dp[i]表示将i和i子树与父亲断开费用 对于父亲x,儿子y ①y为关键点:\(dp[x]\)+=\(dismn( ...
- 【BZOJ】2286: [Sdoi2011]消耗战 虚树+DP
[题意]给定n个点的带边权树,每次询问给定ki个特殊点,求隔离点1和特殊点的最小代价.n<=250000,Σki<=500000. [算法]虚树+DP [题解]考虑普通树上的dp,设f[x ...
- [BZOJ2286][SDOI2011]消耗战(虚树DP)
2286: [Sdoi2011]消耗战 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 4998 Solved: 1867[Submit][Statu ...
- BZOJ 3572 [HNOI2014]世界树 (虚树+DP)
题面:BZOJ传送门 洛谷传送门 题目大意:略 细节贼多的虚树$DP$ 先考虑只有一次询问的情况 一个节点$x$可能被它子树内的一个到x距离最小的特殊点管辖,还可能被管辖fa[x]的特殊点管辖 跑两次 ...
- 洛谷P2495 [SDOI2011]消耗战(虚树dp)
P2495 [SDOI2011]消耗战 题目链接 题解: 虚树\(dp\)入门题吧.虚树的核心思想其实就是每次只保留关键点,因为关键点的dfs序的相对大小顺序和原来的树中结点dfs序的相对大小顺序都是 ...
- BZOJ5287 HNOI2018毒瘤(虚树+树形dp)
显然的做法是暴力枚举非树边所连接两点的选或不选,大力dp.考场上写的是最暴力的O(3n-mn),成功比大众分少10分.容斥或者注意到某些枚举是不必要的就能让底数变成2.但暴力的极限也就到此为止. 每次 ...
- 洛谷 P4426 - [HNOI/AHOI2018]毒瘤(虚树+dp)
题面传送门 神仙虚树题. 首先考虑最 trival 的情况:\(m=n-1\),也就是一棵树的情况.这个我相信刚学树形 \(dp\) 的都能够秒掉罢(确信).直接设 \(dp_{i,0/1}\) 在表 ...
随机推荐
- 调整扩大VMDK格式VirtualBox磁盘空间
如果虚拟机的格式是VDI格式的, 那么可以通过这篇文章来调整磁盘大小: 调整Virtual Box硬盘大小 不过楼主当初在创建虚拟机的时候,是用的VMDK格式, 以求与VMWare的兼容性.这时候要扩 ...
- JS设计模式——7.工厂模式(示例-RSS阅读器)
RSS阅读器 由于我们只想跟RSS容器对象打交道,所以用一个工厂来实例化这些内部对象并把它们组装到一个RSS阅读器中. 使用工厂方法在好处在于,我们创建的RSS阅读器类不会与那些成员对象紧密耦合在一起 ...
- Servlet笔记6--Servlet程序改进
第一步改进,GenericServlet: 我们目前所有放入Servlet类直接实现了javax.servlet.Servlet接口,但是这个接口中有很多方法是目前不需要的,我们可能只需要编写serv ...
- 连接数据库及出现System.AccessViolationException错误的解决方法
调试后发现, connection.Open();以后报错,System.AccessViolationException: 尝试读取或写入受保护的内存.这通常指示其他内存已损坏,网上搜了很多都没有作 ...
- 谈谈Linux内核驱动的coding style【转】
转自:http://www.cnblogs.com/wwang/archive/2011/02/24/1960283.html 最近在向Linux内核提交一些驱动程序,在提交的过程中,发现自己的代码离 ...
- Task多线程进行多进程
using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using Sys ...
- [转载]Windows服务编写原理及探讨(3)
(三)对服务的深入讨论之下 现在我们还剩下一个函数可以在细节上讨论,那就是服务的CtrlHandler函数. 当调用RegisterServiceCtrlHandler函数时,SCM得到并保存这个回调 ...
- 按需引入antd报错问题
1.使用create-react-app工具创建了一个项目 create-react-app antd-demo 2.安装babel-plugin-import npm install babel-p ...
- asterisk各种报错
1.控制台打印出: Got SIP response "Temporarily Unavailable" back from 210.13.87.110:5060 造成原因:在 ...
- 读书笔记--C陷阱与缺陷(四)
第四章 1. 连接器 C语言的一个重要思想就是分别编译:若干个源程序可在不同的时候单独进行编译,恰当的时候整合到一起. 连接器一般与C编译器分离,其输入是一组目标模块(编译后的模块)和库文件,输出是一 ...