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\ ...
随机推荐
- Beta阶段敏捷冲刺报告-DAY2
Beta阶段敏捷冲刺报告-DAY2 Scrum Meeting 敏捷开发日期 2017.11.3 会议时间 13:00 会议地点 微信群 参会人员 项目组全体成员 会议内容 打包问题修复, 爬虫优化, ...
- Ionic3的HTTP请求方法
Ionic的http请求方法,一种是使用Ionic的Native的Http方法,另一种是使用Angular的Http请求方法. 第一种真的是看着文档都实现不了,很奇怪的错(官网文档:https://i ...
- 2017-2018-1 1623 bug终结者 冲刺006
bug终结者 冲刺006 by 20162328 蔡文琛 今日任务:音频素材添加 又是新的一天,小组项目有了很大的起色,已经可以在手机上试玩了. 添加背景音乐能使我们的游戏锦上添花. 音频资源需求 需 ...
- 学号:201621123032 《Java程序设计》第10周学习总结
1:本周学习总结 1.1.:以你喜欢的方式(思维导图或其他)归纳总结异常相关内容. 2:书面作业 2.1.:常用异常--结合题集题目7-1回答 2.1.1:自己以前编写的代码中经常出现什么异常.需要捕 ...
- GitChat招募IT类写作作者
GitChat是一个移动端的IT知识.技术分享平台,于2017.10和CSDN合并,成为其旗下独立品牌. 我们正在寻求有互联网基因的人来一起分享IT人员的关切,诚挚邀请您来做一次分享(让IT类文章变现 ...
- mysql数据库的三范式的设计与理解
一般的数据库设计都需要满足三范式,这是最基本的要求的,最高达到6NF,但是一般情况下3NF达到了就可以 一:1NF一范式的理解: 1NF是关系型数据库中的最基本要求,就是要求记录的属性是原子性,不可分 ...
- Oracle闪回技术
(一)闪回技术概要 闪回技术是数据库备份与恢复的重要补充手段,主要包括以下7种特性: 特性 原理 数据库支持 闪回查询(Flashback Query) 利用undo表空间中的回退信息,查询过去某个时 ...
- Python内置函数(35)——next
英文文档: next(iterator[, default]) Retrieve the next item from the iterator by calling its __next__() m ...
- 单点登录实现机制:桌面sso
参考链接,感谢作者:https://zm10.sm-tc.cn/?src=l4uLj8XQ0IiIiNGckZ2TkJiM0ZyQktCZlo2Mi5uNmp6S0I/QysrJyszPztGXi5K ...
- bootstrap时间区间设置方法
我们在开发过程中经常有时间区间的要求,在多次"失败"及翻阅资料之后终于找到了适合我的方法,所以给大家分享出来. 基本需求为可以设置时间,设置时间区间,后一时间日期不可提前于前一时间 ...