[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的活动,玩家需要根据设置的线索解谜,找到宝藏的位置,前一年获胜的队伍可以获得这一年出题的机会. 作为新生 ...
随机推荐
- C# WebRequest.Create 锚点“#”字符问题
背景 在与后台API接口对接时,如将网页Url作为参数请求数据时,如果是锚点参数,则会丢失. 锚点参数 请求通过WebRequest.Create创建一个WebRequest: var uri = & ...
- 从零开始学安全(四十二)●利用Wireshark分析ARP协议数据包
wireshark:是一个网络封包分析软件.网络封包分析软件的功能是撷取网络封包,并尽可能显示出最为详细的网络封包资料.Wireshark使用WinPCAP作为接口,直接与网卡进行数据报文交换,是目前 ...
- asp.net easyui 动态绑定下拉框
前台: <title>标题</title> <link href="EasyUi_v1.3.4/easyui/themes/default/easyui.css ...
- 学代码第十七天,JAVA继承
JANA面向对象的三大特性:封装,继承,多态. 今天学了继承,继承,通俗点说就是子类可以用父类的代码,或重写父类的方法.构造方法.属性 例如我这里要调用父类的方法: 下边有两个测试类,自己分别试一下, ...
- nginx系列13:最少连接算法以及如何跨worker进程生效
最少连接算法 使用最少连接算法可以使得nginx优先选择连接最少的上游服务器,需要用到upstream_least_conn模块. 如何跨worker进程生效 因为nginx是多进程结构的,默认多个w ...
- Vue slot插槽
插槽用于内容分发,存在于子组件之中. 插槽作用域 父级组件作用域为父级,子级组件作用域为子级,在哪定义的作用域就在哪. 子组件之间的内容是在父级作用域的,无法直接访问子组件里面的数据. 插槽元素 &l ...
- React 16.x 新特性思维导图
React 16版本相对于以前的版本做了很大的改动,下面是我整理的React 16.x 新特性的思维导图文件,欢迎围观和指导:
- Jetty 开发指南:嵌入式开发示例
Jetty具有嵌入各种应用程序的丰富历史. 在本节中,我们将向您介绍我们的git存储库中的embedded-jetty-examples项目下的一些简单示例. 重要:生成此文档时,将直接从我们的git ...
- SpringBoot+MyBatis配置多数据源
SpringBoot 可以支持多数据源,这是一个非常值得学习的功能,但是从现在主流的微服务的架构模式中,每个应用都具有唯一且准确的功能,多数据源的需求很难用到,考虑到实际情况远远比理论复杂的多,这里还 ...
- hbase 过滤器 rowfilter
HBase为筛选数据提供了一组过滤器,通过这个过滤器可以在HBase中的数据的多个维度(行,列,数据版本)上进行对数据的筛选操作,也就是说过滤器最终能够筛选的数据能够细化到具体的一个存储单元格上(由行 ...