[省选联考 2021 A/B 卷] 图函数
一、题目
开始接受\(...\)痛苦不堪的回忆。
二、解法
你看它不用算具体的东西,只用算一个总和,这不用贡献法用什么?
考虑 \(v\) 的贡献,也就是保留 \([v,n]\) 的点和有关边时,和它能互通 \(u\) 点的个数。前 \([1,v)\) 不用考虑是因为如果和 \(u\) 能互通就会删除,如果不互通那么和 \(u\) 不在一个强连通块内,对 \(u,v\) 是否能互通没有任何影响。
枚举点 \(v\),然后跑 \(\tt tarjan\),单次可以做到 \(O(nm)\) 的复杂度。
先固定点 \(v\),考虑删除一个边的前缀的影响,把删边变成加边是老套路了,我们逆序来做。\(\tt tarjan\) 不好维护但考虑到有一个点是定点,所以建出正反图,然后动态 \(\tt bfs\),如果加入的这条边两个端点都访问过就没用,如果终点没有访问过就以他开始 \(\tt bfs\),每次把 \(\tt bfs\) 到的边删掉,如果两个端点都没访问过就加入图中。每条边只会被删除一次,所以时间复杂度 \(O(nm)\)
还有一种方法是考虑点对 \((u,v)\) 的贡献,也就是保留 \([v,n]\) 的点和边时 \(u,v\) 能互通。因为本题边越多 \(u,v\) 更容易互通,所以我们给每个边一个时间(第 \(i\) 条边时间为 \(i\)),可以考虑求出 \(u,v\) 互通的最小瓶颈边最大的路径,那么可知这会贡献给答案序列的一个前缀。
有向图的瓶颈边问题可以考虑 \(\tt floyd\),设 \(f[i][j]\) 表示 \(i\) 到 \(j\) 的最小瓶颈边的最大值,那么考虑枚举中转点 \(k\),有一个限制是 \(k\geq\min(i,j)\),因为图只能保留这些点,在内层循环的时候注意一下即可。
还有一个细节是 \(k\) 要倒序枚举,首先考虑 \(\tt floyd\) 的原理:对于每一条可能的路径,我们通过枚举中转点能把这些点一个一个拼起来,这相当于枚举了所有情况。但是这道题的路径可能是 small->big->middle->big->small
,如果先枚举了small
就会导致路径拼不起来,所以要先枚举big
。
时间复杂度 \(O(n^3)\),真 \(\tt tm\) 怎么做都可以,但是考试时就是不会。
三、总结
当不用求出具体值,只用求总和时,考虑贡献法。
尝试多种翻译方式,比如这道题我一开始翻译的是 \((u,v)\) 强联通,但是因为 \(\tt tarjan\) 不好动态做所以卡了。但是如果翻译成 \((u,v)\) 互通就利于后面想到动态 \(\tt bfs\) 的方法。
#include <cstdio>
#include <iostream>
using namespace std;
const int M = 1005;
int read()
{
int x=0,f=1;char c;
while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
int n,m,f[M][M],ans[200005];
signed main()
{
n=read();m=read();
for(int i=1;i<=m;i++)
{
int u=read(),v=read();
f[u][v]=i;
}
for(int k=n;k>=1;k--)
{
for(int i=1;i<=n;i++)
{
if(!f[i][k]) continue;
int t=f[i][k],up=(i>k)?(k-1):n;
for(int j=1;j<=up;j++)
f[i][j]=max(f[i][j],min(t,f[k][j]));
}
}
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
ans[min(f[i][j],f[j][i])]++;
ans[m+1]=n;
for(int i=m;i>=1;i--) ans[i]+=ans[i+1];
for(int i=1;i<=m+1;i++) printf("%d ",ans[i]);
}
原文地址:https://www.cnblogs.com/C202044zxy/p/15024721.html
- Android Studio配置Kotlin环境
- Android 应用安装过程分析
- React Native之TextInput组件实现联想输入
- React Native之轻量级存储AsyncStorage
- [先行者课程]--0312视差效果--课堂笔记
- Android 绿色应用公约
- React-Native组件之 TabBarIOS和TabBarIOS.Item
- [先行者周日课程-0305] web前端组件 之 拖动窗口
- react-native城市列表组件
- [前端常见病] 之 后端数据还没有,前端怎么进行?
- dependencies与devDependencies的区别
- [先行者课程] -- 用js实现倒计时功能的业务逻辑
- iOS如何实现多个环境一次打包
- 从原理到策略算法再到架构产品看推荐系统 | 附Spark实践案例
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 支持多JDK版本下运行的Jar文件打包方式
- XFF那些事
- Nginx tcp连接反向代理配置
- [Centos 7]免密码异地备份
- smtplib bcc 密送 失败解决方案
- python sys.stdout
- 【8】进大厂必须掌握的面试题-Java面试-异常和线程
- 魔法引用函数magic_quotes_gpc和magic_quotes_runtime的区别和用法
- 在网页中动态的生成一个gif图片
- 在 Visual Basic .NET 或 JScript 代码中使用早期绑定
- 腾讯云TKE-GPU案例: TensorFlow 在TKE中的使用
- 使用pyppeteer 下载chromium 报错 或速度慢
- layui数据表格自定义每页条数limit设置
- dotnet OpenXML 幻灯片 PPTX 的 Slide Id 和页面序号的关系
- springboot 国际化