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

洛谷P2765 思路分享(网络流,二分图匹配)

https://www.luogu.com.cn/problem/P2765

题意概述

\(n\) 根柱子,依次放编号为 $1,2,\cdots $ 的球,每次只能在一根柱子的最上方放球,同一根柱子任意相邻两个球的编号之和必须是完全平方数。

求最多能放多少个球,并构造方案。

思路

考虑用有向边刻画同一根柱子的约束关系,如果 \(u\lt v\),且 \(u+v\) 是完全平方数,连 \(u\)\(v\) 的边,建出是 \(DAG\)。可以发现,这是路径覆盖问题。

考虑二分答案,记球的数量为 \(V\),只需要判断最小路径覆盖是否 \(\le n\) 即可。

求最小路径覆盖是个经典问题,具体做法是,把每个点拆成两个出点和入点,对原图中的边 \(u\)->\(v\),将 \(u\) 的出点连 \(v\) 的入点,然后求最大匹配即可。最小路径覆盖 \(=\) 顶点数 \(-\) 最大匹配。

直觉来看,二分的上界不会太大,同时边的数量也较少,姑且取 \(V^2\) 不会超时的值。代码中取了 \(5005\)

时间复杂度 \(\mathcal{O}(K^2 \log K)\)\(K\) 是二分的上界。建图是 \(\mathcal{O}(V^2)\),边数大概是 \(V\sqrt{V}\),所以 \(dinic\) 求最大匹配是 \(\mathcal{O}(V^2)\),单次二分就是 \(\mathcal{O}(V^2)\)

代码

//author:kzssCCC#include <bits/stdc++.h>
using namespace std;
using ll = long long;class dinic{
public:const ll INF = 9e18;int n,s,t;vector<vector<array<ll,4>>> adj;ll mxf;vector<int> cur,depth;dinic(int _n,int _s,int _t){n = _n;s = _s;t = _t;adj = vector<vector<array<ll,4>>>(n+1);}void add(int u,int v,ll w){adj[u].push_back({w,1,(int)adj[v].size(),v});adj[v].push_back({0,0,(int)adj[u].size()-1,u});}bool bfs(){depth = vector<int>(n+1,-1);queue<int> q;depth[s] = 0;q.push(s);while (!q.empty()){int u = q.front();q.pop();for (auto& [w,flag,rev,v]:adj[u]){if (w>0 && depth[v]==-1){depth[v] = depth[u]+1;q.push(v);}}}return depth[t]!=-1;}ll dfs(int u,ll mf){if (u==t) return mf;ll sum = 0;int len = adj[u].size();for (int& i=cur[u];i<len;i++){auto& [w,flag,rev,v] = adj[u][i];if (w>0 && depth[v]==depth[u]+1){ll f = dfs(v,min(mf,w));sum += f;mf -= f;w -= f;adj[v][rev][0] += f;if (mf==0) break;}}return sum;}void work(){mxf = 0;while (bfs()){cur = vector<int>(n+1);mxf += dfs(s,INF);}}
};const ll INF = 9e18;void solve(){int n;cin >> n;auto pd = [&](int x){int f1 = (int)sqrt(x);int f2 = ceil(sqrt(x));return f1*f1==x || f2*f2==x;};auto check = [&](int mid)->vector<vector<int>>{int N = mid*2+2;int s = N-1;int t = N;dinic dn(N,s,t);for (int i=1;i<=mid;i++){	for (int j=i+1;j<=mid;j++){if (pd(i+j)){dn.add(i,j+mid,1);}}dn.add(s,i,1);dn.add(i+mid,t,1);}dn.work();if (mid-dn.mxf>n){return {};}vector<int> next(mid+1,-1),ing(mid+1);for (int u=1;u<=mid;u++){for (auto& [w,flag,rev,v]:dn.adj[u]){if (flag==1 && w==0){next[u] = v-mid;ing[v-mid]++;}}}int x = 1;vector<vector<int>> res(n+1);vector<bool> vis(mid+1,false);for (int i=1;i<=mid;i++){if (!vis[i] && ing[i]==0){int u = i;while (u!=-1){vis[u] = true;res[x].push_back(u);u = next[u];}x++;}}int y = 1;while (x<=n){while (res[y].size()==1){y++;}	res[x++].push_back(res[y].back());res[y].pop_back();			}return res;};int l=1,r=5005;while (l<=r){int mid = l+(r-l>>1);if (!check(mid).empty()){l = mid+1;}else{r = mid-1;}}int mx = r;auto res = check(mx);cout << mx << '\n';for (int i=1;i<=n;i++){for (auto& v:res[i]){cout << v << ' ';}cout << '\n';}
}int main(){ios::sync_with_stdio(false);cin.tie(0);int t = 1;// cin >> t;while (t--) solve();return 0;
}
http://www.jsqmd.com/news/847470/

相关文章:

  • 嵌入式AI人才培养:产教融合如何破解软硬兼修难题
  • Linux新手看过来:手把手解决TeXLive安装与VSCode配置中的那些“坑”(从镜像下载到环境变量)
  • 化工制造安全生产AI方案主流产品对比详解:2026工业大模型与端到端自动化选型指南
  • 优秘智能解析全国一体化算力网:底层架构如何赋能企业AI应用
  • 时间序列预测实战:从M5竞赛看零售销量预测的挑战与策略
  • 5/19
  • 如何绕过甲骨文云注册时的地址验证风控?
  • Linux按键驱动开发实战:从设备树到输入子系统的完整实现
  • 2026年AI大模型指南:场景化选型,告别“选错模型”的效率陷阱!
  • 【PHPer转Go】函数/方法返回类型的取舍,指针还是值
  • 跨平台流媒体下载神器:N_m3u8DL-RE的完整使用指南
  • CQUPT 2025级 数据科学与大数据技术英才班 周测#06
  • 深入解析Zircon微内核启动流程:从汇编入口到用户态引导
  • ABB伺服驱动抱闸功能详解:从参数设置到点动测试的保姆级指南
  • JDK17对比JDK8:新增核心特性全解析
  • RK3588开发板USB OTG烧录全攻略:从原理到实战避坑指南
  • 能面试完都不错了,脚趾抠地。社招-面经-WDKJ(al)-文本评测方向
  • 终极科学文库PDF解密完整指南:永久解除CAJViewer限制的3步方案
  • 属性、构造方法、Getter)
  • 告别漫长编译!用Docker在5分钟内快速拉起一个可用的SageMath环境(Ubuntu适用)
  • 意图共鸣科技《AI记忆链商业化白皮书2.0》提出“优雅降级”:AI记忆托管如手机保号
  • 【亲测门店】新昌吊车企业哪家靠谱?真实案例分享并附带联系方式 - 花开富贵112
  • 终极指南:7步掌握FanControl,打造完美静音散热系统
  • Tauri应用自动更新实战:从GitHub Actions配置到私钥环境变量避坑全记录
  • MATLAB核心优势解析:七大理由揭秘其在工程与科学领域的不可替代性
  • ESP32 OTA升级避坑指南:用Python脚本一键搭建本地服务器,告别手动配置
  • 【Perplexity医院查询功能深度解密】:3大隐藏缺陷、5步优化方案与2024最新实测数据
  • 医疗 AI Agent 接入 EHR 前,先补齐权限表、审计链和写回状态机
  • GBFR Logs:用数据驱动在《碧蓝幻想Relink》中实现3倍效率提升
  • AI职业成长地图:软件测试从业者的精准发展路径