P9167 [省选联考 2023] 城市建造 题解

news/2025/2/7 16:29:05/文章来源:https://www.cnblogs.com/lupengheyyds/p/18702834

P9167 [省选联考 2023] 城市建造 题解

题面

给定一张 \(n\) 个点 \(m\) 条边的无向连通\(G = (V, E)\),询问有多少该图的子图 \(G' = (V', E')\),满足 \(E' \ne \varnothing\)\(G - E'\) 中恰好有 \(|V'|\) 个连通块,且任意两个连通块大小之差不超过 \(k\),请输出答案对 \(998,244,353\) 取模的结果。

\(0\le k\le 1,3\le n\le 10^5,n-1\le m\le 2\times 10^5\)

解法

首先建出圆方树,可以转化为删去一个方点连通块,使得剩下各连通块圆点的大小极差不超过 \(k\)。其中两个方点联通是指他们有共同的圆点相连。


由于我们想要把这棵树分成若干个大小近乎相等的块,所以划分的方点的位置应该更靠近树的重心 \(R\),于是可以发现第一个性质——重心或重心的方点应该被包括在那个删除方点的连通块中。

于是令 \(R\) 为根,有等价性质——若一个方点被删除,那么其到根的所有方点都应该被删除,于是变为了一颗有根树。


一种圆方树上DP:圆点表示父亲方点,方点表示自己的设计方案。这是一个较为通用的方法, “圆点表示父亲方点”使得可以简单的处理自己的贡献,“方点表示自己”使得可以将各个子树的信息合并

考虑枚举连通块大小 \(d = 1\sim \lfloor \frac n 2\rfloor\)

k = 0

\(R\) 为根树形 DP。设 \(f_i\) 表示:若 \(i\) 是圆点,能否删去其父亲方点(若 \(i\) 为根,则答案可以视为添加并强制删去 \(i\) 的父亲方点时整棵子树的答案);若 \(i\) 是方点,能否删去其本身。 \(f_R\) 即为所求。

  • 对于圆点 \(i\),枚举所有子结点 \(j\)。当 \(sz_j \geq d\) 时,要求 \(f_j = 1\)。否则 \(j\) 不能被删去,因此要求 \(sz_j < d\)\(sz_j\) 之和恰等于 \(d\)

  • 对于方点 \(i\)\(f_i = 1\) 当且仅当其所有子结点 \(j\)\(f_j = 1\)

k = 1

\(k = 0\)\(2\sim \lfloor \frac n 2\rfloor\) 多算了,要减掉。

类似地,设 \(f\_i\) 表示对应方案数, \(f\_R\) 即为所求。

  • 对于圆点 \(i\)

    • \(sz_j < d\),则 \(j\) 不能被删去。

    • \(sz_j > d\),则 \(j\) 必须被删去。

    • 否则 \(sz_j = d\)。当 \(f_j = 0\) 时, \(j\) 不能被删去。否则 \(j\) 可以被删去。

    \(ss\) 为不能被删去的 \(\sum sz_j\) 加上 \(i\) 本身贡献的 \(1\) 表示 \(i\) 的连通块大小最小值,设 \(pd\) 为可以被删去的 \(\prod f_j\)

    • \(ss > d + 1\)\(f_i = 0\)

    • \(d\leq ss\leq d + 1\),则 \(f_i\) 加上 \(pd\)

    • \(ss = 1\),则 \(f_i\) 加上对每个可以被删去的 \(sz_j = d\)\(\frac {pd} {f_j}\) 之和。因为 \(sz_j = d\)\(f_j > 0\)\(f_j = 1\),故 \(\sum \frac {pd} {f_j}\) 等于 \(pd\) 乘以 \(sz_j = d 且 f_j > 0\)\(j\) 的数量 \(cnt\)

    注意第二、三个条件可以同时满足。

  • 对于方点 \(i\)\(f_i\) 等于 \(\prod f_j\)


观察样例发现真正有值的 \(d\) 很少

\(k=0\)\(d|n\)

\(k=1\) 时,\(d=\lfloor \frac n\omega\rfloor\)\(d=\lfloor \frac n\omega\rfloor-1,\omega\in \Z\),表示枚举分成几个连通块。

复杂度为 \(\mathcal O(n^{1.5})\),结合throw可以剪枝

代码(注意那个throw

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int NN=2e5+5,MOD=998244353;
int n,m,k,ans,prod=1;
vector<int> ed[NN],rbt[NN];
int low[NN],dfn[NN],num;
int sta[NN],top,ext,root;
void Tarjan(int x,int fa){dfn[x]=low[x]=++num;sta[++top]=x;for(int y:ed[x]){if(y==fa)continue;if(!dfn[y]){Tarjan(y,x);low[x]=min(low[x],low[y]);if(low[y]>=dfn[x]){int z;ext++;do{z=sta[top--];rbt[ext].push_back(z);rbt[z].push_back(ext);}while(z!=y);rbt[ext].push_back(x);rbt[x].push_back(ext);}}else{low[x]=min(low[x],dfn[y]);}}return;
}
int siz[NN],D,f[NN],MX=0x3f3f3f3f;
void DFS(int x,int fa,bool d){siz[x]=x<=n;int mx=0;for(int y:rbt[x]){if(y==fa)continue;DFS(y,x,d);siz[x]+=siz[y];mx=max(mx,siz[y]);}mx=max(mx,n-siz[x]);if(d&&MX>mx){MX=mx,root=x;}return;
}
void DFS0(int x,int fa){if(x<=n){f[x]=1;int sum=1;for(int y:rbt[x]){if(y==fa)continue;DFS0(y,x);if(siz[y]<D)sum+=siz[y];else f[x]&=f[y];}    f[x]&=sum==D;}else{f[x]=1;for(int y:rbt[x]){if(y==fa)continue;DFS0(y,x);if(siz[y]<D)f[x]=0;else f[x]&=f[y];}}
}
void Deal(int d,int sign=1){if(d==n)return;D=d;DFS0(root,root);(ans+=f[root]*sign)%=MOD;return;
}
void DFS1(int x,int fa){if(x<=n){//圆点 int sum=1,prod=1,cnt=0;for(int y:rbt[x]){if(y==fa)continue;DFS1(y,x);if(siz[y]<D)sum+=siz[y];else if(siz[y]>D)(prod*=f[y])%=MOD;else if(f[y])(prod*=f[y])%=MOD,cnt++,assert(f[y]==1);else sum+=siz[y];}f[x]=0;if(D<=sum&&sum<=D+1)f[x]=prod;if(sum==1)(f[x]+=prod*cnt%MOD)%=MOD;}else{//方点f[x]=1;for(int y:rbt[x]){if(y==fa)continue;DFS1(y,x);(f[x]*=f[y])%=MOD;}}if(siz[x]>D&&!f[x])throw "Grimgod";//throw大法好 return;
}
void Deal1(int d){D=d;try{DFS1(root,root);(ans+=f[root])%=MOD;}catch(...){}return;
}
signed main(){ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);cin>>n>>m>>k;ext=n;for(int i=1;i<=m;i++){int u,v;cin>>u>>v;ed[u].push_back(v);ed[v].push_back(u);}Tarjan(1,1);DFS(1,1,1);memset(siz,0,sizeof siz);DFS(root,root,0);if(!k){for(int d=1;d*d<=n;d++){if(n%d==0){Deal(d);if(d*d!=n)Deal(n/d);}}cout<<ans;}else{vector<int> tmp;for(int d=2;d<=n/2;d++)tmp.push_back(n/d),tmp.push_back(n/d-1);sort(tmp.begin(),tmp.end());tmp.erase(unique(tmp.begin(),tmp.end()),tmp.end());for(int o:tmp)Deal1(o);for(int d=2;d<=n/2;d++)if(n%d==0)Deal(d,-1);cout<<(ans+MOD)%MOD;}return 0;
}/*
应该是割方点连通块 
----------------------------------------------------
没有想到 
性质:那个删除的方点连通块一定想要包括树的重心 
一种圆方树上DP:圆点表示父亲方点,方点表示自己的设计方案。这是一个较为通用的方法, “圆点表示父亲方点”使得可以简单的处理自己的贡献,“方点表示自己”使得可以将各个子树的信息合并
k=1的圆点的情况比较复杂,需要好好想才能想清楚。
这样才想出来75分的做法 
----------------------------------------------------
75->100是想出来的:
观察样例发现真正有值的d很少,
结合k=0的情况进一步分析,假设此时分为了 k 个连通块,那么d=n/k或d=n/k-1
复杂度为 O(n^{1.5}),结合throw可以剪枝 
*/

参考

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/880103.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

高标准农田智慧管理系统

随着科技的飞速发展,智慧农业已成为推动农业现代化的重要力量。高标准农田智慧管理系统作为智慧农业的核心组成部分,正逐步改变着传统农业的生产方式。本文将深入探讨高标准农田智慧管理系统的建设内容,以期为我国农业的可持续发展提供新的思路和方向。一、高标准农田智慧管…

老年人评估系统web端

项目结构项目实现 用到了springboot mybatis框架 vue ajax axios element 成品效果自动刷新的信息查询点击注册跳转 跳转之后的注册页面点击返回可回到主页面点击删除按钮跳转的页面点击更正信息弹出的form表单 项目功能基本实现

【土地交易大揭秘】哪些用地必须走“招拍挂”之路?

今天咱们来聊聊一个在土地市场里热度颇高的话题——哪些用地必须通过招标、拍卖或者挂牌方式出让?这可是关乎城市建设和房地产开发的大事,对投资者和普通市民来说,了解这一点至关重要。下面,我们就来深入浅出地解读一番。招标、拍卖、挂牌出让简述首先,普及一下基本概念。…

python脚本与命令行交互sys.argv

前言在 Python 编程的世界里,sys.argv 是一个强大且实用的工具,它为我们开启了与命令行交互的大门,让程序能够接收外部传入的参数,从而实现更加灵活和多样化的功能。今天,就让我们深入探索 sys.argv 的奥秘。 “argv” 即 “argument value” 是一个列表对象,其中存储的是…

奶奶都能看懂的 CSS 选择器基础语法常用属性优先级

标题都是奶奶都能看懂了,那么我们肯定从最基础的开始讲。之所以这么自信是因为能踩的坑全帮你们踩过了…… 开始之前,先来首诗感受一下,具体啥意思你看完本文就懂了。 点类井号逗为或,类多号单连为且。 id 优先类在后,类型选择在末尾。 代码优先难解决,拿出鼠标数一数。 …

本地部署大模型体验小记

本地部署大模型的工具工具 优缺点LM Studio 图形界面友好,支持API访问,参数配置灵活Ollama GPU优化不足,CPU占用率高Chatbox 易出现输入卡顿,交互体验待优化Ollama 和 Chatbox 需要配合使用。 综合看更推荐使用 LM Studio 。 自定义模型 LM Studio 和 Ollama 除了使用默认的…

oi-math 重修

OI 数学重修 注: 很多东西没来得及写例题和代码,以后遇到会补上 想了一下虽然还有很多没写完,但是这两天要开数学了,决定后面的分成一个一个博客写然后在这挂链接,所以发出来了。 主题是看着 oi-wiki 写的,但细节上尤其是证明部分不太一样,毕竟也不是什么教学性质的,权…

方差、标准差、变异系数举例

一、标准差,也称均方差,是方差的算术平方根,标准差能反映一个数据集的离散程度。平均数相同的两组数据,标准差未必相同。太绕了,上例子:1、先找出平均数。平均数是数据的平均值,把数据加起来然后除以数据个数就可以得到。2、再找出方差。方差是数据偏离平均数的程度。得…

中电金信:大咖漫话|如何营销AI赋能的远程银行

看过“从远程银行看AIGC”连载,今天将与各位漫话AI的营销“哲学”。祝各位事业蟠蟠,巳巳如意,我们开年再会!

miniconda配置及常用命令,windows系统环境变量设置

安装完miniconda后,如果cmd中输入"conda info"没有输出信息,说明需要手动配置环境变量。 (1)右键点击桌面上“此电脑”,点击“属性” (2)在弹出的页面里点击“高级系统设置”(3)点击“环境变量”(4)双击“系统变量”里面的"Path":(5)点击“新…