[HNOI/AHOI2018]毒瘤
题目描述
题解
大意:给出一张n个点n+x条边的无向连通图,x很小,求出这个图上最大独立集的方案数。
感觉就是NOIP保卫王国那题的加强版吧。
暴力的话,我们可以考虑在图上随便找一颗生成树,然后把非树边连接的点设置为关键点,然后2^x枚举这些点的选择情况,每次做一遍树形dp就好了。
如果做到这里,那么可以自然而然的想到一个优化:虚树。
就是发现在虚树上的非关键点部分的转移相似,所以我们可以预处理出这些东西来。
我们设f[i][0/1]表示i点的所有不包含关键点的子树的答案。
对于关键点到关键点的转移,我们可以设k[i][0/1][0/1]表示关键点i点到i点的第一个关键点祖先的儿子处i点和那个儿子的选择情况的方案数。
这个直接从i点向上跳,边跳边统计答案就可以算出来了。
注意虚树上的LCA点也要标为关键点。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#include<vector>
#define N 110009
using namespace std;
typedef long long ll;
const int mod=;
vector<int>vec[N];
inline int rd(){
int x=;char c=getchar();bool f=;
while(!isdigit(c)){if(c=='-')f=;c=getchar();}
while(isdigit(c)){x=(x<<)+(x<<)+(c^);c=getchar();}
return f?-x:x;
}
struct node{int u,v;}ed[];
ll k[N][][],g[N][],f[N][],ans;
int tot,head[N],dfn[N],p[][N],deep[N],a[N],ttt,n,m,st[N],top;
bool vis[N],dy1[N],dy0[N],tag[N];
struct edge{int n,to;}e[N<<];
inline void add(int u,int v){e[++tot].n=head[u];e[tot].to=v;head[u]=tot;}
inline void add2(int u,int v){tag[u]=;tag[v]=;vec[u].push_back(v);}////!!!!!!!!!
void dfs(int u,int fa){
dfn[u]=++dfn[];vis[u]=;
for(int i=;(<<i)<=deep[u];++i)p[i][u]=p[i-][p[i-][u]];
for(int i=head[u];i;i=e[i].n)if(e[i].to!=fa){
int v=e[i].to;
if(!vis[v]){deep[v]=deep[u]+;p[][v]=u;dfs(v,u);}
else{a[++a[]]=u;a[++a[]]=v;ed[++ttt]=node{u,v};}
}
}
inline bool cmp(int a,int b){return dfn[a]<dfn[b];}
inline int getlca(int a,int b){
if(deep[a]<deep[b])swap(a,b);
for(int i=;i>=;--i)if(deep[a]-(<<i)>=deep[b])a=p[i][a];
if(a==b)return a;
for(int i=;i>=;--i)if(p[i][a]!=p[i][b])a=p[i][a],b=p[i][b];
return p[][a];
}
void predp(int u,int jin){
f[u][]=f[u][]=;tag[u]=;
for(int i=head[u];i;i=e[i].n){
int v=e[i].to;
if(p[][v]!=u||v==jin||tag[v])continue;
predp(v,jin);
f[u][]=f[u][]*(f[v][]+f[v][])%mod;
f[u][]=f[u][]*f[v][]%mod;
}
}
inline void getnum(int x,int y){
k[x][][]=k[x][][]=;
for(int i=x;p[][i]!=y;i=p[][i]){
predp(p[][i],i);
ll xx=k[x][][],yy=k[x][][];
k[x][][]=f[p[][i]][]*(k[x][][]+k[x][][])%mod;
k[x][][]=f[p[][i]][]*xx%mod;
k[x][][]=f[p[][i]][]*(k[x][][]+k[x][][])%mod;
k[x][][]=f[p[][i]][]*yy%mod;
}
}
void prework(int u){
for(int i=;i<vec[u].size();++i){
int v=vec[u][i];
prework(v);getnum(v,u);
}
f[u][]=f[u][]=;
for(int i=head[u];i;i=e[i].n){
int v=e[i].to;
if(p[][v]!=u||tag[v])continue;
predp(v,);
f[u][]=f[u][]*(f[v][]+f[v][])%mod;
f[u][]=f[u][]*f[v][]%mod;
}
}
void dp(int u){
g[u][]=f[u][];g[u][]=f[u][];
if(dy1[u])g[u][]=;if(dy0[u])g[u][]=;
for(int i=;i<vec[u].size();++i){
int v=vec[u][i];
dp(v);
ll k0=(k[v][][]*g[v][]%mod+k[v][][]*g[v][]%mod)%mod,k1=(k[v][][]*g[v][]%mod+k[v][][]*g[v][]%mod)%mod;
g[u][]=g[u][]*(k0+k1)%mod;g[u][]=g[u][]*k0%mod;
}
}
int main(){
n=rd();m=rd();int u,v;
for(int i=;i<=m;++i){
u=rd();v=rd();
add(u,v);add(v,u);
}
dfs(,);sort(a+,a+a[]+,cmp);
a[]=unique(a+,a+a[]+)-a-;
st[top=]=;
for(int i=;i<=a[];++i){
tag[a[i]]=;
if(a[i]==st[top])continue;
int lca=getlca(st[top],a[i]);
if(lca==st[top]){st[++top]=a[i];continue;}
while(top>){
int x=st[top],y=st[top-];
if(dfn[lca]>=dfn[y]){add2(lca,x);top--;break;}
add2(y,x);top--;
}
if(st[top]!=lca)st[++top]=lca;
if(st[top]!=a[i])st[++top]=a[i];
}
while(top>)add2(st[top-],st[top]),top--;
prework();
for(int i=;i<(<<a[]);++i){
for(int j=;j<=a[];++j)if(i&(<<j-))dy1[a[j]]=,dy0[a[j]]=;else dy0[a[j]]=,dy1[a[j]]=;
bool tagg=;
for(int j=;j<=ttt;++j){
int u=ed[j].u,v=ed[j].v;
if(dy1[u]&&dy1[v]){tagg=;break;}
}
if(tagg)continue;
dp();
(ans+=g[][]+g[][])%=mod;
}
cout<<ans;
return ;
}
[HNOI/AHOI2018]毒瘤的更多相关文章
- #10 //I [HNOI/AHOI2018]毒瘤
题解: 80分做法还是听简单的 对于非树边枚举一下端点状态 然而我也不知道为什么就多t了一个点 具体实现上 最暴力的是3^n次 但是我们可以发现对于i不取,j取 i不取,j不取是可以等效成i不取,j没 ...
- P4426 [HNOI/AHOI2018]毒瘤
挺不错的一个题. 题意即为求一个图的独立集方案数. 如果原图是一棵树,可以直接大力f[x][0/1]来dp. 由于非树边很少,考虑2^11容斥,强制某些点必选,然后再O(n)dp,这样应该过不了. 发 ...
- Luogu P4426 [HNOI/AHOI2018]毒瘤
题目 神仙题. 首先我们可以把题意转化为图的独立集计数.显然这个东西是个NP-Hard的. 然后我们可以注意到\(m\le n+10\),也就是说最多有\(11\)条非树边. 我们现在先考虑一下,树上 ...
- 题解 [HNOI/AHOI2018]毒瘤
题目传送门 题目大意 给出一个 \(n\) 个点 \(m\) 条边的无向图,问有多少个点集满足点集中任意两点均不存在边相连. \(n\le 10^5,m-n\le 10\),答案对 \(9982443 ...
- 洛谷 P4426 - [HNOI/AHOI2018]毒瘤(虚树+dp)
题面传送门 神仙虚树题. 首先考虑最 trival 的情况:\(m=n-1\),也就是一棵树的情况.这个我相信刚学树形 \(dp\) 的都能够秒掉罢(确信).直接设 \(dp_{i,0/1}\) 在表 ...
- [HNOI/AHOI2018]转盘(线段树优化单调)
gugu bz lei了lei了,事独流体毒瘤题 一句话题意:任选一个点开始,每个时刻向前走一步或者站着不动 问实现每一个点都在$T_i$之后被访问到的最短时间 Step 1 该题可证: 最优方案必 ...
- 【LG4437】[HNOI/AHOI2018]排列
[LG4437][HNOI/AHOI2018]排列 题面 洛谷 题解 题面里这个毒瘤的东西我们转化一下: 对于\(\forall k,j\),若\(p_k=a_{p_j}\),则\(k<j\). ...
- 【题解】Luogu P4436 [HNOI/AHOI2018]游戏
原题传送门 \(n^2\)过百万在HNOI/AHOI2018中真的成功了qwqwq 先将没门分格的地方连起来,枚举每一个块,看向左向右最多能走多远,最坏复杂度\(O(n^2)\),但出题人竟然没卡(建 ...
- [Bzoj5285][洛谷P4424][HNOI/AHOI2018]寻宝游戏(bitset)
P4424 [HNOI/AHOI2018]寻宝游戏 某大学每年都会有一次Mystery Hunt的活动,玩家需要根据设置的线索解谜,找到宝藏的位置,前一年获胜的队伍可以获得这一年出题的机会. 作为新生 ...
随机推荐
- Java HashMap 使用了未经检查或不安全的操作
今天在做接口测试的时候使用了Java中的Map(java 所知胜少,因项目需要提供示例),不扯犊子了,我们直接看一个代码文件名:Test.java: import java.util.ArrayLis ...
- 授权管理-LDAP-介绍与环境搭建
LDAP介绍 转自:https://blog.csdn.net/tanshizhen119/article/details/79942315 还是先来百度百科介绍. LDAP是轻量目录访问协议,英文全 ...
- html 微信video放大后无法返回问题
android video播放视频放大后无法返回,先debug下debugx5.qq.com 发现用的不是X5内核 直接激活 debugmm.qq.com/?forcex5=true 问题解决 ...
- [置顶]生鲜配送管理系统_升鲜宝V2.0 销售订单汇总_采购任务分配功能_操作说明
做好生鲜供应链系统,要注意三个方面,1.分拣 2 采购 3 库存,市面上做的比较成熟的功能,还是分拣这一块(按客户分拣.按订单分拣.按商品分类分拣.按商品分拣.按线路分拣.客户自由组合分拣)[下篇文 ...
- android常犯错误记录(三)
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionVie ...
- vs code配置flutter开发android
下载flutter_sdk压缩包,解压到指定目录,把sdk的bin目录添加到系统环境变量Path 设置中国临时镜像:添加两个系统变量 FLUTTER_STORAGE_BASE_URL=https:// ...
- 未能加载文件或程序集“System.Web.Mvc, Version=5.2.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35”或它的某一个依赖项
楼主创建项目的时候选择的是5.2.4的版本,但是后来改成了5.0.0于是出现了这个错误,解决的方法倒也简单 将View文件夹下 web.config文件中 以下两处 版本改成当前版本就行了
- 黑阔主流攻防之不合理的cookie验证方式
最近博主没事干中(ZIZUOZISHOU),于是拿起某校的习题研究一番,名字很6,叫做黑阔主流攻防习题 虚拟机环境经过一番折腾,配置好后,打开目标地址:192.168.5.155 如图所示 这里看出题 ...
- mysql解压包安装教程
1.下载压缩包,地址1(官网下载):https://www.mysql.com/downloads/ 地址2(百度网盘):https://pan.baidu.com/s/12lnpcr3thBe9 ...
- 随机IP
function rand_ip(){ $ip_longs = array( array('607649792', '608174079'), //36.56.0.0-36.63.255 ...