Problem

BZOJ

Solution

顾名思义,如果不是暴力分比较多,的确是一道很毒瘤的题。。

题面中所谓的联通操作就是保证互斥的连边后,是一个连通图。我们从树的状态考虑起。不妨设f[x][1/0]表示子树x中x选/不选时合法的方案数。
容易得到转移方程f[x][1]=∏f[son][0],f[x][0]=∏(f[son][0]+f[son][1])f[x][1]=∏f[son][0],f[x][0]=∏(f[son][0]+f[son][1])f[x][1]=\prod f[son][0],f[x][0]=\prod (f[son][0]+f[son][1])

那么对于加入的非树边应该怎么办呢,我们可以去掉环上的一边,使得它变成树,将这个边的作用看做约束条件,即x,y不能同时选中。注意到此时有合法的三种状态即(1,0),(0,1),(0,0),那么我们对每条非树边枚举状态再DP算贡献,时间复杂度为O(3m−n+1n)O(3m−n+1n)O(3^{m-n+1}n)

我们可以把状态合并成两个状态,改成枚举dfs序更小的点选不选,因为当它不选时,另一个点可以选也可以不选,合并起来转移即可做到O(2m−n+1n)O(2m−n+1n)O(2^{m-n+1}n)。这个时候的暴力分已经很多了。

如果你大力推公式,你可以发现,除了非树边约束的两个点,其它的dp都可以预处理转移的系数。那么我们考虑建立一棵虚树,然后dfs暴力转移出系数,并把系数关系化成虚树上边的权值,然后就可以做了。时间复杂度是s=m−n+1,O(n+s2s)s=m−n+1,O(n+s2s)s=m-n+1,O(n+s2^s)。

Code

#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int maxn=100100,mod=998244353;
inline int pls(int x,int y){return x+y>=mod?x+y-mod:x+y;}
template <typename Tp> inline void read(Tp &x)
{x=0;int f=0;char ch=getchar();while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();if(ch=='-') f=1,ch=getchar();while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();if(f) x=-x;
}
struct data{int v,nxt;}edge[maxn<<1];
struct factor{int x,y;factor(){}factor(int _x,int _y){x=_x;y=_y;}factor operator + (const factor &t){return factor(pls(x,t.x),pls(y,t.y));}factor operator * (const int t){return factor((ll)x*t%mod,(ll)y*t%mod);}
}k[maxn][2];
struct data2{int v,nxt;factor a,b;}ed[maxn];
int n,m,ep,edp,ans,dfc,cnt,head[maxn],h[maxn],dfn[maxn],mark[maxn],sz[maxn];
int vis[maxn],p[maxn][2],st[maxn][2],f[maxn][2];
pii e[20];
inline void insert(int u,int v){edge[++ep]=(data){v,head[u]};head[u]=ep;}
inline void insert(int u,int v,factor a,factor b)
{ed[++edp]=(data2){v,h[u],a,b};h[u]=edp;
}
int dfs(int x,int pre)
{dfn[x]=++dfc;for(int i=head[x];i;i=edge[i].nxt)if(edge[i].v^pre){if(!dfn[edge[i].v]) sz[x]+=dfs(edge[i].v,x);//sz表示有几棵子树中有虚树节点else{mark[x]=1;//mark标记虚树节点if(dfn[edge[i].v]>dfn[x]) e[++cnt]=make_pair(x,edge[i].v);}}mark[x]|=(sz[x]>1);//这说明x是虚树上的一个lcareturn sz[x]||mark[x];
}
int build(int x)
{int pos=0,w,v;p[x][0]=p[x][1]=1;vis[x]=1;//p是自己的dp,k用于累加虚树边的系数for(int i=head[x];i;i=edge[i].nxt)if(!vis[edge[i].v]){v=edge[i].v;w=build(v);if(!w){p[x][0]=(ll)p[x][0]*pls(p[v][0],p[v][1])%mod;p[x][1]=(ll)p[x][1]*p[v][0]%mod;}else if(mark[x]) insert(x,w,k[v][0]+k[v][1],k[v][0]);else k[x][0]=k[v][0]+k[v][1],k[x][1]=k[v][0],pos=w;//此时只会有一个虚树节点,否则mark[x]=1}if(mark[x]) k[x][0]=factor(1,0),k[x][1]=factor(0,1),pos=x;else k[x][0]=k[x][0]*p[x][0],k[x][1]=k[x][1]*p[x][1];return pos;//子树中深度最小的虚树节点
}
void input()
{int x,y;read(n);read(m);for(int i=1;i<=m;i++){read(x);read(y);insert(x,y);insert(y,x);}dfs(1,0);mark[1]=1;build(1);
}
void dp(int x)
{int f0,f1;f[x][0]=st[x][1]?0:p[x][0];f[x][1]=st[x][0]?0:p[x][1];for(int i=h[x];i;i=ed[i].nxt){dp(ed[i].v);f0=f[ed[i].v][0];f1=f[ed[i].v][1];f[x][0]=(ll)f[x][0]*pls((ll)ed[i].a.x*f0%mod,(ll)ed[i].a.y*f1%mod)%mod;f[x][1]=(ll)f[x][1]*pls((ll)ed[i].b.x*f0%mod,(ll)ed[i].b.y*f1%mod)%mod;}
}
int main()
{#ifndef ONLINE_JUDGEfreopen("in.txt","r",stdin);#endifinput();int lim=1<<cnt;for(int i=0;i<lim;i++){for(int j=1;j<=cnt;j++){if(i&(1<<j-1)) st[e[j].first][1]=st[e[j].second][0]=1;else st[e[j].first][0]=1;}dp(1);ans=pls(ans,pls(f[1][0],f[1][1]));for(int j=1;j<=cnt;j++){if(i&(1<<j-1)) st[e[j].first][1]=st[e[j].second][0]=0;else st[e[j].first][0]=0;}}printf("%d\n",ans);return 0;
}

BZOJ5287 HNOI2018毒瘤相关推荐

  1. # HNOI2012 ~ HNOI2018 题解

    HNOI2012 题解 [HNOI2012]永无乡 Tag:线段树合并.启发式合并 联通块合并问题. 属于\(easy\)题,直接线段树合并 或 启发式合并即可. [HNOI2012]排队 Tag:组 ...

  2. yyb省选前的一些计划

    突然意识到有一些题目的计划,才可以减少大量查水表或者找题目的时间. 所以我决定这样子处理. 按照这个链接慢慢做. 当然不可能只做省选题了. 需要适时候夹杂一些其他的题目. 比如\(agc/arc/cf ...

  3. HNOI2018 摸鱼记

    HNOI2018 摸鱼记 今天我又来记流水账啦 Day 0 颓废的一天. 我,球爷和杜教在颓膜膜.io ych看起来在搓碧蓝 鬼知道哥达鸭干了什么 学习氛围只局限在机房的一角 后来全体Oier开会,5 ...

  4. [BZOJ3337] ORZJRY I --块状链表大毒瘤

    link 题目大意:维护一个序列 支持: 1.单点插入 2.单点删除 3.区间翻转 4.区间旋转 5.区间加 6.区间赋值 7.询问区间和 8.询问区间极差 9.询问区间与给定某个数差值绝对值的最小值 ...

  5. 毒瘤题No.006-byFHS

    毒瘤题No.006-byFHS 题目背景 暂无 题目描述 给你一个无向图,求最少用多少棵树来覆盖这个图上的所有边 输入格式 第1行:两个数\(n,m\),表示有\(n\)个点,\(m\)条边 接下来\ ...

  6. 约会安排 (区间合并)毒瘤题

    约会安排 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submi ...

  7. 「AHOI / HNOI2018」转盘 解题报告

    「AHOI / HNOI2018」转盘 可能是我语文水平不太行... 首先可以猜到一些事实,这个策略一定可以被一个式子表示出来,不然带修修改个锤子. 然后我们发现,可以枚举起点,然后直接往前走,如果要 ...

  8. 【UOJ#67】新年的毒瘤 Tarjan 割点

    #67. 新年的毒瘤 UOJ直接黏贴会炸...    还是戳这里吧: http://uoj.ac/problem/67#tab-statement Solution 看到这题的标签就进来看了一眼. 想 ...

  9. HNOI2018游记

    HNOI2018游记 day 0 上午稍微写了下题保持手感,然后看了一下套路,感觉不会的还是不会. 下午去划水在湖面上被吹成傻逼... 感觉没有联赛前那么紧张了,应该是联赛考挂了的原因吧.. day1 ...

  10. Potato的暑期训练day#1题解 ——毒瘤构造

    Potato的暑期训练day#1 --毒瘤构造 题目链接: A.https://vjudge.net/problem/HDU-1214 B.https://vjudge.net/problem/Cod ...

最新文章

  1. SUSE LINUX下文件系统变只读的问题解决
  2. 内部人看FaceBook
  3. 项目:网站架构,集群
  4. Alpha 冲刺 (7/10)
  5. 使用ffmpeg进行h.264编码
  6. .net winform panel 不刷新_winform项目——仿QQ即时通讯程序04:登录界面补充
  7. java mysql存储图片_Java存储图片到Mysql
  8. Windows开启SSH连接
  9. 如何统计网页的浏览量?Steins
  10. [lua]紫猫lua教程-命令宝典-L1-01-09. string字符串函数库
  11. 【Windows】win7虚拟机安装VMware Tools
  12. 重定向与重定位的理解
  13. JavaWeb期末考试复习资料
  14. 【避坑指“难”】页面Top置顶(返回顶部)小图标实现逻辑
  15. 支付宝小程序模板开发,协助商家一键创建小程序
  16. labview2015安装DAQmx助手之后无法使用的问题
  17. 如何使用svn导出项目
  18. 移动端网页打印代码_安卓移动端直接打印文档方法,无需开电脑
  19. 索引全扫描与索引快速扫描的区别
  20. 【2022考研最后40天】要注意这4个时间节点和这5件事情

热门文章

  1. 360 路由器设置 虚拟服务器,360安全路由器的设置方法
  2. 如何实现不规则的Div外部形状?
  3. 原价游戏太贵?爬取steam游戏优惠信息
  4. 13.2.3 VAM服务器的配置步骤及示例(2)
  5. 微信表情的字符编号完整版【图文并茂哦 】
  6. an error occurred while creating opening the c++ browsing database 解决办法
  7. snappy流式编解码总结
  8. ZZULIOJ:1132: 数字字符统计
  9. java与设计模式-观察者模式
  10. c++学习笔记 第四部分