当前位置: 首页 > news >正文

10.03模拟赛t3

CF475E Strongly Connected City 2

题目描述

想象有一座城市,这座城市有 \(n\) 个路口和 \(m\) 条街道。路口编号从 \(1\)\(n\)

为了提高交通流量,市长决定将每条街道改为单行道。这意味着在连接路口 \(u\)\(v\) 的街道上,交通只能从 \(u\)\(v\),或只能从 \(v\)\(u\) 单向通行。

现在的问题是,需要为这些街道指定单向通行的方向,使得能够到达的点对 \((u, v)\) 的数量最大,其中 \(1 \le u, v \le n\),且要求从 \(u\) 出发经过指定方向的街道能够到达 \(v\)。你的任务是找出最大可能的此类点对数量。

题解:

先大概猜猜,发现一个简单的性质,对于一个环,一定满足全部都一个方向最优秀。

所以我们先做一个 tarjan。点权为环的点数。然后发现贪心不大行,考虑 dp

这个时候还要一个性质,对于最优解。就是在只在重心上,能满足其一部分子树的所有点能到达他,其他点都可以从他到达。

证明:

考虑有一个小联通快所有边的方向与其他不同,那么发现把这个所有边全部翻转过来,答案一定变大,因为重心一侧的点至少为所有点的一半。

这下就可以 dp 了。我们把重心作为根,考虑每个点的贡献是多少:

  • (除 \(root\))自己 \(\times\) 自己的子树和

  • 通过重心的到达另一端

其实就是要判断那些子树进入,那些子树要出去。

我们发现第一个贡献不论怎么分配都是一样的。

第二个贡献实际上是一个数学问题:设你进入的节点总数为 \(x\),重心点权为 \(y\) 另一侧点的数量和为 \(z\)。那么有答案为 \((x+y)\times (y+z)\)

那其实就是要找到每一个 \(x\) 能不能被表示出来,这是一个典型的 01背包 直接做复杂度 \(O(n^2)\)bitset 维护的话是 \(\frac{n^2}{w}\) 的。

code:

#include<bits/stdc++.h>
#define pb push_back
#define int long long
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;
const int N=2e5+10;
int n,m,k,T,a[N],vis[N],dfn[N];
int low[N],tot,col,scc[N],siz[N];
int rt,mx=INT_MAX,sz[N],ans,sum;
vector<int> g[N],g1[N];
stack<int> st;
void tar(int u,int fa){dfn[u]=low[u]=++tot;vis[u]=1;st.push(u);for(int v:g[u]){if(v==fa) continue;if(!dfn[v]){tar(v,u);low[u]=min(low[u],low[v]);}else if(vis[v]) low[u]=min(low[u],dfn[v]);}if(low[u]==dfn[u]){col++;while(1){int t=st.top();st.pop();scc[t]=col;vis[t]=0;siz[col]++;if(t==u) break;}}
}
void getrt(int u,int fa){sz[u]=siz[u];int res=0;for(int v:g1[u]){if(v==fa) continue;getrt(v,u);sz[u]+=sz[v];res=max(res,sz[v]);}res=max(res,n-sz[u]);if(res<mx) mx=res,rt=u;
}
void dfs(int u,int fa){sz[u]=siz[u];for(int v:g1[u]){if(v==fa) continue;dfs(v,u);sz[u]+=sz[v];}if(fa)sum+=siz[u]*sz[u];
}
bitset<N> s; 
signed main(){ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);cin>>n>>m;rep(i,1,m){int u,v;cin>>u>>v;g[u].pb(v);g[v].pb(u);}tar(1,0);rep(i,1,n){for(int v:g[i]){if(scc[i]!=scc[v]){g1[scc[i]].pb(scc[v]);}}}rt=0;getrt(1,0);dfs(rt,0);s[0]=1;if(g1[rt].size()==n-1){cout<<1ll*((n-1)/2)*(n-((n-1)/2))+(n-((n-1)/2)-1)+n;return 0;	}for(int v:g1[rt]){s=s|(s<<sz[v]);}rep(i,0,n){if(s[i]==1){ans=max(ans,(i+siz[rt])*(n-i));}}cout<<ans+sum;return 0;
}
http://www.hskmm.com/?act=detail&tid=23632

相关文章:

  • 国庆梦熊集训做题记录
  • 文件的逻辑结构
  • python 肘部法则,判点聚类分为几类,K-means聚类分析
  • AT_abc315_f [ABC315F] Shortcuts
  • 紫外UV固化太阳光模拟器的原理 - 教程
  • 每日一题
  • P5709 【深基2.习6】Apples Prologue / 苹果和虫子
  • 问题表 - microsoft
  • Leetcode 736. Lisp 语法解析
  • Day10.1
  • SolarWinds Web Help Desk远程代码执行漏洞分析
  • Aria2安装
  • 正则表达式学习
  • 深入解析:[特殊字符]函数指针:C语言的动态灵魂,嵌入式的超能力(202589)
  • 《电路基础》第八章学习笔记
  • 《电路基础》第七章学习笔记
  • LLM大模型:deepseek sparse attention是个啥?
  • Day10
  • 软著申请全流程材料模板,2025年最新模板汇总! - 实践
  • 手把手教你使用 Docker 部署 Nginx 教程
  • CF2129 CF1951 VP 记录
  • PWN-BUUCTF-test_your_nc
  • 详细介绍:计算机视觉:OpenCV+Dlib 人脸检测
  • python 老生常谈的找2个excel相同列的行,把其中一个excel行的对应的值放入到另一个excel中
  • 实用指南:淘宝团购上线:本地生活的“两种解法”
  • 【K8S】Kubernetes 调度器深度解析:原理与源码分析
  • 快速幂算法的基础和扩展
  • 堆叠集成
  • 概率与决策 - 模拟程序让你在选择中取胜
  • 题解:qoj6504 Flowers Land 2