题目

神仙题。

首先我们可以把题意转化为图的独立集计数。显然这个东西是个NP-Hard的。

然后我们可以注意到\(m\le n+10\),也就是说最多有\(11\)条非树边。

我们现在先考虑一下,树上独立集计数怎么做。

设\(f_{u,0/1}\)表示\(u\)点选/不选的方案数。

那么转移方程就是:

\(f_{u,0}=\prod\limits_{v\in son_u}(f_{v,0}+f_{v,1})\)

\(f_{u,1}=\prod\limits_{v\in son_u}f_{v,0}\)

最后的答案就是\(f_{1,0}+f_{1,1}\)。

然后我们知道现在有最多\(11\)条非树边,我们可以枚举每条非树边两端的状态,然后再跑一遍dp。

这样每条非树边有\((0,0),(0,1),(1,0)\)三种情况。可以发现\((0,0),(0,1)\)这两种情况可以合并。这样就变成枚举每条非树边的起点选不选。

所以我们就得到了一个\(O(n2^{m-n+1})\)的优秀做法。根据常数可以获得\(70\sim80\)分的好成绩。

然后我们来想一件事情,我们每次做dp的时候,有很多转移是浪费的。

我们可以把每个点的\(f\)看做一个向量,那么转移就可以看做是一个矩阵。

然后我们会发现转移基本上都是不变的,变的只是我们枚举强制选不选的那些点的向量。

这启发我们用虚树来处理dp部分。

把枚举强制选不选的那些点看做是关键点,然后对于它们建一棵虚树,然后dp。

所以现在我们需要求的就是虚树上的一条边(对应原树上的一条链)的转移的系数,这个东西我们可以通过在原树上自下而上dfs一遍求得。这个过程可能有点麻烦。

实际上建虚树的过程也可以在上面这个dfs的过程中来完成。

然后我们就可以在虚树上面跑dp了,时间复杂度为\(O(n+(m-n+1)2^{m-n+1})\)。

#include<bits/stdc++.h>
#define pb push_back
#define pi pair<int,int>
#define fi first
#define se second
using namespace std;
namespace IO
{
char ibuf[(1<<21)+1],*iS,*iT;
char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
int read(){int x=0,c=Get();while(!isdigit(c))c=Get();while(isdigit(c))x=x*10+c-48,c=Get();return x;}
}using namespace IO;
const int N=100020,P=998244353;
int inc(int a,int b){return a+=b,a>=P? a-P:a;}
int mul(int a,int b){return 1ll*a*b%P;}
int n,m;
namespace Graph
{
vector<int>E[N];int T,cnt,dfn[N],size[N],vis[N],fa[N];
struct edge{int u,v;}e[N];
void add(int u,int v){E[u].pb(v),E[v].pb(u);}
void dfs(int u)
{
dfn[u]=++T;
for(int v:E[u])
if(v^fa[u])
if(!dfn[v]) fa[v]=u,dfs(v),size[u]+=size[v];
else if(dfn[v]<dfn[u]) e[++cnt]={u,v},vis[u]=vis[v]=1;
vis[u]|=size[u]>=2,size[u]=size[u]||vis[u];
}
}using namespace Graph;
namespace ITree
{
int f[N][2],g[N][2],p[N][2],is[N];pi k[N][2];
pi operator+(pi a,pi b){return pi(inc(a.fi,b.fi),inc(a.se,b.se));}
pi operator*(pi a,int k){return pi(mul(k,a.fi),mul(k,a.se));}
struct node{int v;pi a,b;};vector<node>G[N];
void Add(int u,int v,pi a,pi b){G[u].pb({v,a,b});}
int build(int u)
{
p[u][0]=p[u][1]=1,is[u]=1;int pos=0,w;
for(int v:E[u])
if(!is[v])
{
w=build(v);
if(!w) p[u][1]=mul(p[u][1],p[v][0]),p[u][0]=mul(p[u][0],inc(p[v][0],p[v][1]));
else if(vis[u]) Add(u,w,k[v][0]+k[v][1],k[v][0]);
else k[u][1]=k[v][0],k[u][0]=k[v][0]+k[v][1],pos=w;
}
if(vis[u]) k[u][0]=pi(1,0),k[u][1]=pi(0,1),pos=u; else k[u][0]=k[u][0]*p[u][0],k[u][1]=k[u][1]*p[u][1];
return pos;
}
void dp(int u)
{
(f[u][0]=g[u][1]? 0:p[u][0]),(f[u][1]=g[u][0]? 0:p[u][1]);
for(auto [v,a,b]:G[u])
{
dp(v);int p=f[v][0],q=f[v][1];
f[u][0]=mul(f[u][0],inc(mul(a.fi,p),mul(a.se,q)));
f[u][1]=mul(f[u][1],inc(mul(b.fi,p),mul(b.se,q)));
}
}
}using namespace ITree;
int main()
{
n=read(),m=read();int ans=0;
for(int i=1,u,v;i<=m;++i) u=read(),v=read(),add(u,v);
dfs(1),vis[1]=1,build(1);
for(int S=0,i;S<1<<cnt;++S)
{
for(i=1;i<=cnt;++i) if(S>>(i-1)&1) g[e[i].u][1]=g[e[i].v][0]=1; else g[e[i].u][0]=1;
dp(1),ans=inc(ans,inc(f[1][1],f[1][0]));
for(i=1;i<=cnt;++i) if(S>>(i-1)&1) g[e[i].u][1]=g[e[i].v][0]=0; else g[e[i].u][0]=0;
}
printf("%d",ans);
}

Luogu P4426 [HNOI/AHOI2018]毒瘤的更多相关文章

  1. P4426 [HNOI/AHOI2018]毒瘤

    挺不错的一个题. 题意即为求一个图的独立集方案数. 如果原图是一棵树,可以直接大力f[x][0/1]来dp. 由于非树边很少,考虑2^11容斥,强制某些点必选,然后再O(n)dp,这样应该过不了. 发 ...

  2. 洛谷 P4426 - [HNOI/AHOI2018]毒瘤(虚树+dp)

    题面传送门 神仙虚树题. 首先考虑最 trival 的情况:\(m=n-1\),也就是一棵树的情况.这个我相信刚学树形 \(dp\) 的都能够秒掉罢(确信).直接设 \(dp_{i,0/1}\) 在表 ...

  3. 【题解】Luogu P4436 [HNOI/AHOI2018]游戏

    原题传送门 \(n^2\)过百万在HNOI/AHOI2018中真的成功了qwqwq 先将没门分格的地方连起来,枚举每一个块,看向左向右最多能走多远,最坏复杂度\(O(n^2)\),但出题人竟然没卡(建 ...

  4. luogu P4437 [HNOI/AHOI2018]排列

    luogu 问题本质是把\(a_i\)作为\(i\)的父亲,然后如果有环就不合法,否则每次要取数,要满足取之前他的父亲都被取过(父亲为0可以直接取),求最大价值 贪心想法显然是要把权值大的尽量放在后面 ...

  5. [HNOI/AHOI2018]毒瘤

    题目描述 https://www.lydsy.com/JudgeOnline/upload/201804/%E6%B9%96%E5%8D%97%E4%B8%80%E8%AF%95%E8%AF%95%E ...

  6. 【题解】Luogu P4438 [HNOI/AHOI2018]道路

    原题传送门 实际就是一道简单的树形dp 设f[u][i][j]表示从根结点到结点u经过i条未翻修公路,j条未翻修铁路的贡献最小值 边界条件:f[leaf][i][j]=(A+i)(B+j)C (题目上 ...

  7. #10 //I [HNOI/AHOI2018]毒瘤

    题解: 80分做法还是听简单的 对于非树边枚举一下端点状态 然而我也不知道为什么就多t了一个点 具体实现上 最暴力的是3^n次 但是我们可以发现对于i不取,j取 i不取,j不取是可以等效成i不取,j没 ...

  8. Luogu 4438 [HNOI/AHOI2018]道路

    $dp$. 这道题最关键的是这句话: 跳出思维局限大胆设状态,设$f_{x, i, j}$表示从$x$到根要经过$i$条公路,$j$条铁路的代价,那么对于一个叶子结点,有$f_{x, i, j} = ...

  9. Luogu P4436 [HNOI/AHOI2018]游戏

    题目 我们要求出\(l_i,r_i\)表示\(i\)最远能够到达的最左边和最右边的格子. 首先有一个比较简单的暴力,就是每次我们选择一个格子,然后从当前格子开始往左右暴力扩展,找到能够到达的最远的格子 ...

随机推荐

  1. Codeforces 55D. Beautiful numbers(数位DP,离散化)

    Codeforces 55D. Beautiful numbers 题意 求[L,R]区间内有多少个数满足:该数能被其每一位数字都整除(如12,24,15等). 思路 一开始以为是数位DP的水题,觉得 ...

  2. 【java设计模式】-00目录

    开篇 [java设计模式]-01设计模式简介 创建型模式: [java设计模式]-02工厂模式(Factory Pattern) [java设计模式]-03抽象工厂模式(Abstract Factor ...

  3. JavaWeb_(Spring框架)在Struts+Hibernate框架中引入Spring框架

    spring的功能:简单来说就是帮我们new对象,什么时候new对象好,什么时候销毁对象. 在MySQL中添加spring数据库,添加user表,并添加一条用户数据 使用struts + hibern ...

  4. mac使用frida

    mac使用frida 安装 https://github.com/frida/frida/releases 根据手机的cpu的版本,选择相应的文件,一般通过手机信息可以看到 我这里是frida-ser ...

  5. 【sed】基本用法

    1. 文本处理 sed编辑器根据sed命令处理数据流中的数据:在流编辑器将所有命令与一行数据匹配完后,它会读取下一行数据并重复以下过程: (1) 一次从输入中读取一行数据 (2) 根据所提供的编辑器命 ...

  6. CISCO实验记录三:CDP邻居发现

    一.CDP邻居发现要求 1.识别二层连接 2.识别CDP邻居 二.CDP邻居发现操作 1.CDP邻居发现 #interface gigabitEthernet 0/0/0 //启动端口 #no shu ...

  7. 2159 -- Ancient Cipher

    Ancient Cipher Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 36074   Accepted: 11765 ...

  8. Vue UI组件 开发框架 服务端 辅助工具 应用实例 Demo示例

    Vue UI组件 开发框架 服务端 辅助工具 应用实例 Demo示例 element ★11612 - 饿了么出品的Vue2的web UI工具套件 Vux ★7503 - 基于Vue和WeUI的组件库 ...

  9. 定位上下文(补充css的position属性)

    ]把元素的position属性设定为relative.absolute或fixed后,继而可以使用TRBL属性,相对于另一个元素移动该元素的位置.这里的“另一个元素”,就是该元素的定位上下文. 绝对定 ...

  10. 如何快速通过json构建javabean对象(Intellij IDEA-->GsonFormat使用教程)

    和第三方对接的时候,返回给我们的json时参数字段多是很常见的现象,所以我们手动去创建javabean肯定是要花费不少时间,博主在网上找到了很多种,可用通过json自动生成javabean的工具,这里 ...