3246. 引水入城

题目链接

3246. 引水入城

MF 城建立在一片高原上。

由于城市唯一的水源是位于河谷地带的湖中,人们在坡地上修筑了一片网格状的抽水水管,以将湖水抽入城市。

如下图所示:

image

这片管网由 nm 列节点(红色,图中 n=5m=6),横向管道(紫色)和纵向管道(橙色)构成。

行和列分别用 1n 的整数和 1m 的整数表示。

1 行的任何一个节点均可以抽取湖水,湖水到达第 n 行的任何一个节点即算作引入了城市。

除第一行和最后一行外,横向相邻或纵向相邻的两个节点之间一定有一段管道,每一段管道都有各自的最大的抽水速率,并需要根据情况选择抽水还是放水。

对于纵向的管道(橙色),允许从上方向下方抽水或从下方向上方放水;如果从图中的上方向下方抽水,那么单位时间内能通过的水量不能超过管道的最大速率;如果从下方向上方放水,因为下方海拔较高,因此可以允许有任意大的水量。

对于横向的管道(紫色),允许从左向右或从右向左抽水,不允许放水,两种情况下单位时间流过的水量都不能超过管道的最大速率。

现在 MF 城市的水务负责人想知道,在已知每个管道单位时间容量的情况下,MF 城每单位时间最多可以引入多少的湖水。

输入格式

由于输入规模较大,我们采用伪随机生成的方式生成数据。

每组数据仅一行包含 6 个非负整数 n,m,A,B,Q,X0。其中,nm 如前文所述,表示管网的大小,保证 2n,m5000;保证 1A,B,Q,X0109

A,B,Q,X_0 是数据生成的参数,我们用如下的方式定义一个数列 {Xi}

Xi+1=(AXi+B)modQ,(i0)

我们将数列的第 1 项到第 (n1)m 项作为纵向管道的单位时间容量,其中 X(s1)m+t 表示第 s 行第 t 列的节点到第 s+1 行第 t 列管道单位时间的容量;将数列的第 (n1)m+1 项到第 (n1)m+(n2)(m1) 项(即接下来的 (n2)(m1) 项)作为横向管道的单位时间容量,其中 X(n1)m+(s2)(m1)+t 表示第 s 行第 t 列的节点到第 s 行第 t+1 列管道单位时间的容量。

输出格式

输出一行一个整数,表示 MF 城每单位时间可以引入的水量。

注意计算过程中有些参数可能超过 32 位整型表示的最大值,请注意使用 64 位整型存储相应数据。

数据范围

共有 10 组评测数据,每组数据的参数规模如下所示:

image

输入样例1:

3 3 10 3 19 7

输出样例1:

38

样例1解释

使用参数得到数列 {Xi}={7,16,11,18,12,9,17,2,4,},按照输入格式可以得到每个管道的最大抽水量如下图所示:

image

在标准答案中,单位时间可以引水 38 单位。所有纵向管道均向下抽水即可,不需要横向管道抽水,也不需要向上放水。

输入样例2:

2 5 595829232 749238243 603779819 532737791

输出样例2:

1029036148

输入样例3:

5 2 634932890 335818535 550589587 977780683

输出样例3:

192923706

输入样例4:

5 5 695192542 779962396 647834146 157661239

输出样例4:

1449991168

解题思路

分层图,最小割转平面图最短路

显然,如果不考虑数据范围,本题为最大流板题,即建立源点 s 和 汇点 ts 向所有的第一行的点连边,容量足够大,最后一行的点向 t 连边,容量足够大,其余边权在流网络中即为容量,求解 st 的最大流即为所求,但显然本题数据范围不允许,由最大流最小割定理,=,而该图又为一个平面图,可知 =,具体见 P4001 [ICPC-Beijing 2006] 狼抓兔子,则现在只用求解最短路即可,但 O(nlogn) 的算法也无法通过本题,考虑性质,由于向上的边的容量足够大,最短路必不会选择该边,即列与列之间的传递是单向的,很容易发现这是一个每一列每一列的分层图,而且在每一层中的某个点,其是一条链,即只能从上或者下转移过来,而列与列之间只有一个方向
另外还需要注意对偶图平面的编号,这里不再赘述

  • 时间复杂度:O(nm)

代码

// Problem: 引水入城 // Contest: AcWing // URL: https://www.acwing.com/problem/content/3249/ // Memory Limit: 512 MB // Time Limit: 3000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> //#define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } const int N=5005; int n,m,A,B,Q,x; LL f[N][N],w[N][N]; int main() { memset(f,0x3f,sizeof f); memset(w,0x3f,sizeof w); scanf("%d%d%d%d%d%d",&n,&m,&A,&B,&Q,&x); for(int i=1;i<=n;i++)f[i][0]=0; for(int i=1;i<n;i++) for(int j=1;j<=m;j++) f[i][j]=x=((LL)A*x+B)%Q; for(int i=1;i<n-1;i++) for(int j=1;j<m;j++) w[i][j]=x=((LL)A*x+B)%Q; for(int j=1;j<=m;j++) { for(int i=1;i<n;i++) { f[i][j]+=f[i][j-1]; f[i][j]=min(f[i][j],f[i-1][j]+w[i-1][j]); } for(int i=n-2;i;i--) f[i][j]=min(f[i][j],f[i+1][j]+w[i][j]); } LL res=1e18; for(int i=1;i<n;i++)res=min(res,f[i][m]); printf("%lld",res); return 0; }

__EOF__

本文作者acwing_zyy
本文链接https://www.cnblogs.com/zyyun/p/16953668.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zyy2001  阅读(51)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示