Description

Solution

\(dfs\) 出一棵生成树之后,多出来的边就都是反祖边了

把反祖边两个端点都拿出来,就会得到最多 \(k=2*(m-n+1)\) 个关键点

除了关键点以外的点转移都是一样的,我们可以预处理出来

关键点数量不多,我们 \(2^k\) 枚举状态,然后像树形 \(DP\) 一样转移就行了

转移需要构一棵虚树,对于虚树上的一条边,对应在原树上的一条链转移也是一样的

如果知道了虚树上 \(x\) 的 \(DP\) 值,\(f[x][0],f[x][1]\),那么就可以推出虚树上的父亲的值 \(f[fa[x]][0],f[fa[x]][1]\)

大致可以表示成这样的形式:\(f[fa[x]][0]=k0*f[x][0]+k1*f[x][1]\),\(f[fa[x]][1]\) 同理

对于转移系数和虚树上某些节点的 \(DP\) 初值都可以 \(O(n*k)\) 的预处理出来

对于一条边 \((x,y)\),只有三种状态:存在 \(x\),存在 \(y\),都不存在,所以状态数实际上只有 \(3^{\frac{k}{2}}\)

复杂度是 \(O(n*k+3^{\frac{k}{2}}*k)\)

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10,mod=998244353;
int n,m,head[N],nxt[N*4],to[N*4],num=1,st[N],top=0,sq[N],fa[N][20];
int ST[N*2],TOP=0,dfn[N],DFN=0,tp=0,dep[N],q[N],r=0,Head[N],id[N];
inline bool comp(int i,int j){return dfn[i]<dfn[j];}
inline void link(int x,int y){nxt[++num]=head[x];to[num]=y;head[x]=num;}
inline void Link(int x,int y){nxt[++num]=Head[x];to[num]=y;Head[x]=num;}
inline int LCA(int x,int y){
if(dep[x]<dep[y])swap(x,y);
int deep=dep[x]-dep[y];
for(int i=19;i>=0;i--)if(deep>>i&1)x=fa[x][i];
if(x==y)return x;
for(int i=19;i>=0;i--)
if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
bool vis[N],et[N*4];int imp[N],lim,ans=0,f[N][2],lis[N];
struct data{
int k0,k1;
data(){}
data(int _k0,int _k1){k0=_k0;k1=_k1;}
inline data operator +(data &t){return data((k0+t.k0)%mod,(k1+t.k1)%mod);}
inline data operator *(int t){
return data(1ll*k0*t%mod,1ll*k1*t%mod);}
inline int F(int x,int y){return (1ll*x*k0+1ll*y*k1)%mod;}
}k[N][2];
inline void build(int x,int last){
vis[x]=1;dfn[x]=++DFN;
for(int i=head[x];i;i=nxt[i]){
if(i==last)continue;
int u=to[i];
if(!vis[u])fa[u][0]=x,dep[u]=dep[x]+1,build(u,i^1);
else if(dep[u]<dep[x])st[++top]=x,sq[top]=u,et[i]=et[i^1]=1;
}
}
int dp[N][2];bool d[N];
inline void calc(int x,int la){
dp[x][0]=dp[x][1]=1;
for(int i=head[x];i;i=nxt[i]){
int u=to[i];
if(u==la || u==fa[x][0] || d[u])continue;
calc(u,la);
dp[x][0]=1ll*dp[x][0]*(dp[u][0]+dp[u][1])%mod;
dp[x][1]=1ll*dp[x][1]*dp[u][0]%mod;
}
}
inline void getit(int S,int T){
int x=S;
k[x][0]=data(1,0);k[x][1]=data(0,1);
while(fa[x][0]!=T){
calc(fa[x][0],x);
data t=k[S][0];d[fa[x][0]]=1;
k[S][0]=(k[S][0]+k[S][1])*dp[fa[x][0]][0];
k[S][1]=t*dp[fa[x][0]][1];
x=fa[x][0];
}
}
inline void DFS(int x){
for(int i=Head[x];i;i=nxt[i]){
DFS(to[i]);
getit(to[i],x);
}
dp[x][0]=dp[x][1]=1;
for(int i=head[x];i;i=nxt[i]){
int u=to[i];
if(u==fa[x][0] || d[u] || et[i])continue;
calc(u,x);
dp[x][0]=1ll*dp[x][0]*(dp[u][0]+dp[u][1])%mod;
dp[x][1]=1ll*dp[x][1]*dp[u][0]%mod;
}
}
inline void dfs(int x){
f[x][0]=dp[x][0];f[x][1]=dp[x][1];
for(int i=Head[x];i;i=nxt[i]){
int u=to[i],f0,f1;
dfs(u);
f0=k[u][0].F(f[u][0],f[u][1]);
f1=k[u][1].F(f[u][0],f[u][1]);
f[x][0]=1ll*f[x][0]*(f0+f1)%mod;
f[x][1]=1ll*f[x][1]*f0%mod;
}
if(imp[x]!=-1)f[x][imp[x]^1]=0;
}
int main(){
freopen("duliu.in","r",stdin);
freopen("duliu.out","w",stdout);
int x,y;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
link(x,y);link(y,x);
} dep[1]=1;build(1,-1);
for(int j=1;j<20;j++)
for(int i=1;i<=n;i++)fa[i][j]=fa[fa[i][j-1]][j-1];
for(int i=1;i<=top;i++)ST[++TOP]=st[i],ST[++TOP]=sq[i];
sort(ST+1,ST+TOP+1,comp);
tp=unique(ST+1,ST+TOP+1)-ST-1;
int cnt=0;
for(int i=1;i<=tp;i++)lis[++cnt]=ST[i];
lis[++cnt]=1;
sort(lis+1,lis+cnt+1,comp);
cnt=unique(lis+1,lis+cnt+1)-lis-1;
for(int i=1;i<=tp;i++)id[ST[i]]=i-1; q[++r]=lis[1];
for(int i=2;i<=cnt;i++){
x=lis[i];
int lca=LCA(x,lis[i-1]);d[lca]=1;
while(r && dfn[q[r]]>dfn[lca]){
if(dfn[q[r-1]]>dfn[lca])Link(q[r-1],q[r]);
else {
Link(lca,q[r]);r--;
if(q[r]!=lca)q[++r]=lca;break;
}
r--;
}
q[++r]=lis[i];
}
while(r>1)Link(q[r-1],q[r]),r--; for(int i=1;i<=cnt;i++)d[lis[i]]=1;
DFS(1);lim=(1<<tp)-1;
memset(imp,-1,sizeof(imp));
for(int i=0;i<=lim;i++){
bool flag=1;
for(int j=1;j<=top;j++)
if((i>>id[st[j]]&1) && (i>>id[sq[j]]&1)){flag=0;break;}
if(!flag)continue;
for(int j=1;j<=tp;j++)imp[ST[j]]=i>>(j-1)&1;
dfs(1);
ans=((ans+f[1][0])%mod+f[1][1])%mod;
}
cout<<ans<<endl;
return 0;
}

bzoj 5287: [Hnoi2018]毒瘤的更多相关文章

  1. BZOJ 5287: [Hnoi2018]毒瘤 动态dp(LCT+矩阵乘法)

    自己 yy 了一个动态 dp 做法,应该是全网唯一用 LCT 写的. code: #include <bits/stdc++.h> #define ll long long #define ...

  2. 【BZOJ5287】[HNOI2018]毒瘤(动态规划,容斥)

    [BZOJ5287][HNOI2018]毒瘤(动态规划,容斥) 题面 BZOJ 洛谷 题解 考场上想到的暴力做法是容斥: 因为\(m-n\le 10\),所以最多会多出来\(11\)条非树边. 如果就 ...

  3. 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] ...

  4. [bzoj5287] [HNOI2018]毒瘤

    题目描述 从前有一名毒瘤. 毒瘤最近发现了量产毒瘤题的奥秘.考虑如下类型的数据结构题:给出一个数组,要求支持若干种奇奇怪怪的修改操作(比如区间加一个数,或者区间开平方),并支持询问区间和.毒瘤考虑了n ...

  5. [HNOI2018]毒瘤

    Description 从前有一名毒瘤. 毒瘤最近发现了量产毒瘤题的奥秘.考虑如下类型的数据结构题:给出一个数组,要求支持若干种奇奇怪怪的修改操作(比如区间加一个数,或者区间开平方),并支持询问区间和 ...

  6. bzoj 5286: [Hnoi2018]转盘

    Description Solution 首先注意到一个点不会走两次,只会有停下来等待的情况,把序列倍长 那么如果枚举一个起点\(i\),答案就是 \(min(max(T[j]+n-(j-i)-1)) ...

  7. bzoj 5285: [Hnoi2018]寻宝游戏

    Description Solution 把输入的 \(n\) 个二进制数看作一个大小为 \(n*m\) 的矩阵 把每一列压成一个二进制数,其中最高位是最下面的元素 然后就有了 \(m\) 个二进制数 ...

  8. bzoj 5289: [Hnoi2018]排列

    Description Solution 首先注意到实际上约束关系构成了一棵树 考虑这个排列 \(p\),编号为 \(a[i]\) 的出现了,\(i\) 才可以出现 那么如果连边 \((a[i],i) ...

  9. bzoj 5288: [Hnoi2018]游戏

    Description Solution 乱搞能A的题,毁我青春 记忆化一下扩展过程 只要不是从 \(1\) 枚举到 \(n\) 去扩展都可以 \(AC\) 于是 \(random\_shuffle\ ...

随机推荐

  1. [福大软工] W班 团队第一次作业—团队展示成绩公布

    作业地址 https://edu.cnblogs.com/campus/fzu/FZUSoftwareEngineering1715W/homework/906 作业要求 根据已经组队的队伍组成, 每 ...

  2. Java作业-数据库

    本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结与数据库相关内容. 在Java中使用数据库要经过以下几个步骤: 1. 注册 JDBC 驱动 Class.forName("com ...

  3. 1013团队Beta冲刺日志集合帖

    Beta预备 Beta冲刺day1 Beta冲刺day2 Beta冲刺day3 Beta冲刺day4 Beta冲刺day5 Beta冲刺day6 Beta冲刺day7 用户使用调查报告 Beta冲刺总 ...

  4. Beta集合

    Beta冲刺day1 Beta冲刺day2 Beta冲刺day3 Beta冲刺day4 Beta冲刺day5 Beta冲刺day6 Beta冲刺day7 测试总结 总结合集 Beta预备

  5. 2017 清北济南考前刷题Day 3 afternoon

    期望得分:100+40+100=240 实际得分:100+40+100=240 将每个联通块的贡献乘起来就是答案 如果一个联通块的边数>点数 ,那么无解 如果边数=点数,那么贡献是 2 如果边数 ...

  6. hdu 5274 Dylans loves tree

    Dylans loves tree http://acm.hdu.edu.cn/showproblem.php?pid=5274 Time Limit: 2000/1000 MS (Java/Othe ...

  7. poj 2142 The Balance

    The Balance http://poj.org/problem?id=2142 Time Limit: 5000MS   Memory Limit: 65536K       Descripti ...

  8. vue 在methods中调用mounted中的方法?

    首先可以在data中先声明一个变量 比如 isShow=' ' mounted 中 ---> methods 中 --->  this.sureDelBox(item) 直接this调用 ...

  9. SpringCloud的应用发布(三)vmvare+linux,xftp,xshell连接linux失败

    Vmvare内的linux虚拟机已经启动,但是 xftp和xshell连接不上? 环境信息:子网 192.168.136.* linux ip:192.168.136.100 一.核对linux的ip ...

  10. eclipse开发Groovy代码,与java集成,maven打包编译

    今天尝试了一下在eclipse里面写Groovy代码,并且做到和Java代码相互调用,折腾了一下把过程记录下来. 首先需要给eclipse安装一下Groovy的插件,插件地址:https://gith ...