bzoj 5287: [Hnoi2018]毒瘤
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]毒瘤的更多相关文章
- BZOJ 5287: [Hnoi2018]毒瘤 动态dp(LCT+矩阵乘法)
自己 yy 了一个动态 dp 做法,应该是全网唯一用 LCT 写的. code: #include <bits/stdc++.h> #define ll long long #define ...
- 【BZOJ5287】[HNOI2018]毒瘤(动态规划,容斥)
[BZOJ5287][HNOI2018]毒瘤(动态规划,容斥) 题面 BZOJ 洛谷 题解 考场上想到的暴力做法是容斥: 因为\(m-n\le 10\),所以最多会多出来\(11\)条非树边. 如果就 ...
- 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] ...
- [bzoj5287] [HNOI2018]毒瘤
题目描述 从前有一名毒瘤. 毒瘤最近发现了量产毒瘤题的奥秘.考虑如下类型的数据结构题:给出一个数组,要求支持若干种奇奇怪怪的修改操作(比如区间加一个数,或者区间开平方),并支持询问区间和.毒瘤考虑了n ...
- [HNOI2018]毒瘤
Description 从前有一名毒瘤. 毒瘤最近发现了量产毒瘤题的奥秘.考虑如下类型的数据结构题:给出一个数组,要求支持若干种奇奇怪怪的修改操作(比如区间加一个数,或者区间开平方),并支持询问区间和 ...
- bzoj 5286: [Hnoi2018]转盘
Description Solution 首先注意到一个点不会走两次,只会有停下来等待的情况,把序列倍长 那么如果枚举一个起点\(i\),答案就是 \(min(max(T[j]+n-(j-i)-1)) ...
- bzoj 5285: [Hnoi2018]寻宝游戏
Description Solution 把输入的 \(n\) 个二进制数看作一个大小为 \(n*m\) 的矩阵 把每一列压成一个二进制数,其中最高位是最下面的元素 然后就有了 \(m\) 个二进制数 ...
- bzoj 5289: [Hnoi2018]排列
Description Solution 首先注意到实际上约束关系构成了一棵树 考虑这个排列 \(p\),编号为 \(a[i]\) 的出现了,\(i\) 才可以出现 那么如果连边 \((a[i],i) ...
- bzoj 5288: [Hnoi2018]游戏
Description Solution 乱搞能A的题,毁我青春 记忆化一下扩展过程 只要不是从 \(1\) 枚举到 \(n\) 去扩展都可以 \(AC\) 于是 \(random\_shuffle\ ...
随机推荐
- [福大软工] W班 团队第一次作业—团队展示成绩公布
作业地址 https://edu.cnblogs.com/campus/fzu/FZUSoftwareEngineering1715W/homework/906 作业要求 根据已经组队的队伍组成, 每 ...
- Java作业-数据库
本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结与数据库相关内容. 在Java中使用数据库要经过以下几个步骤: 1. 注册 JDBC 驱动 Class.forName("com ...
- 1013团队Beta冲刺日志集合帖
Beta预备 Beta冲刺day1 Beta冲刺day2 Beta冲刺day3 Beta冲刺day4 Beta冲刺day5 Beta冲刺day6 Beta冲刺day7 用户使用调查报告 Beta冲刺总 ...
- Beta集合
Beta冲刺day1 Beta冲刺day2 Beta冲刺day3 Beta冲刺day4 Beta冲刺day5 Beta冲刺day6 Beta冲刺day7 测试总结 总结合集 Beta预备
- 2017 清北济南考前刷题Day 3 afternoon
期望得分:100+40+100=240 实际得分:100+40+100=240 将每个联通块的贡献乘起来就是答案 如果一个联通块的边数>点数 ,那么无解 如果边数=点数,那么贡献是 2 如果边数 ...
- hdu 5274 Dylans loves tree
Dylans loves tree http://acm.hdu.edu.cn/showproblem.php?pid=5274 Time Limit: 2000/1000 MS (Java/Othe ...
- poj 2142 The Balance
The Balance http://poj.org/problem?id=2142 Time Limit: 5000MS Memory Limit: 65536K Descripti ...
- vue 在methods中调用mounted中的方法?
首先可以在data中先声明一个变量 比如 isShow=' ' mounted 中 ---> methods 中 ---> this.sureDelBox(item) 直接this调用 ...
- SpringCloud的应用发布(三)vmvare+linux,xftp,xshell连接linux失败
Vmvare内的linux虚拟机已经启动,但是 xftp和xshell连接不上? 环境信息:子网 192.168.136.* linux ip:192.168.136.100 一.核对linux的ip ...
- eclipse开发Groovy代码,与java集成,maven打包编译
今天尝试了一下在eclipse里面写Groovy代码,并且做到和Java代码相互调用,折腾了一下把过程记录下来. 首先需要给eclipse安装一下Groovy的插件,插件地址:https://gith ...