题目链接
3246. 引水入城
MF 城建立在一片高原上。
由于城市唯一的水源是位于河谷地带的湖中,人们在坡地上修筑了一片网格状的抽水水管,以将湖水抽入城市。
如下图所示:
这片管网由 \(n\) 行 \(m\) 列节点(红色,图中 \(n = 5\),\(m = 6\)),横向管道(紫色)和纵向管道(橙色)构成。
行和列分别用 \(1\) 到 \(n\) 的整数和 \(1\) 到 \(m\) 的整数表示。
第 \(1\) 行的任何一个节点均可以抽取湖水,湖水到达第 \(n\) 行的任何一个节点即算作引入了城市。
除第一行和最后一行外,横向相邻或纵向相邻的两个节点之间一定有一段管道,每一段管道都有各自的最大的抽水速率,并需要根据情况选择抽水还是放水。
对于纵向的管道(橙色),允许从上方向下方抽水或从下方向上方放水;如果从图中的上方向下方抽水,那么单位时间内能通过的水量不能超过管道的最大速率;如果从下方向上方放水,因为下方海拔较高,因此可以允许有任意大的水量。
对于横向的管道(紫色),允许从左向右或从右向左抽水,不允许放水,两种情况下单位时间流过的水量都不能超过管道的最大速率。
现在 MF 城市的水务负责人想知道,在已知每个管道单位时间容量的情况下,MF 城每单位时间最多可以引入多少的湖水。
输入格式
由于输入规模较大,我们采用伪随机生成的方式生成数据。
每组数据仅一行包含 \(6\) 个非负整数 \(n, m, A, B, Q, X_0\)。其中,\(n\) 和 \(m\) 如前文所述,表示管网的大小,保证 \(2 ≤ n, m ≤ 5000\);保证 \(1 ≤ A, B, Q, X_0 ≤ 10^9\)。
\(A, B, Q, X\_0\) 是数据生成的参数,我们用如下的方式定义一个数列 \(\{ X_i \}\):
\(X_{i+1} = ( AX_i + B) \bmod Q, (i ≥ 0)\)
我们将数列的第 \(1\) 项到第 \((n-1)m\) 项作为纵向管道的单位时间容量,其中 \(X_{(s-1)m+t}\) 表示第 \(s\) 行第 \(t\) 列的节点到第 \(s+1\) 行第 \(t\) 列管道单位时间的容量;将数列的第 \((n-1)m+1\) 项到第 \((n-1)m+(n-2)(m-1)\) 项(即接下来的 \((n-2)(m-1)\) 项)作为横向管道的单位时间容量,其中 \(X_{(n-1)m+(s-2)(m-1)+t}\) 表示第 \(s\) 行第 \(t\) 列的节点到第 \(s\) 行第 \(t+1\) 列管道单位时间的容量。
输出格式
输出一行一个整数,表示 MF 城每单位时间可以引入的水量。
注意计算过程中有些参数可能超过 \(32\) 位整型表示的最大值,请注意使用 \(64\) 位整型存储相应数据。
数据范围
共有 \(10\) 组评测数据,每组数据的参数规模如下所示:
输入样例1:
3 3 10 3 19 7
输出样例1:
38
样例1解释
使用参数得到数列 \(\{ X_i \}=\{ 7, 16, 11, 18, 12, 9, 17, 2, 4, … \}\),按照输入格式可以得到每个管道的最大抽水量如下图所示:
在标准答案中,单位时间可以引水 \(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\) 和 汇点 \(t\),\(s\) 向所有的第一行的点连边,容量足够大,最后一行的点向 \(t\) 连边,容量足够大,其余边权在流网络中即为容量,求解 \(s\) 到 \(t\) 的最大流即为所求,但显然本题数据范围不允许,由最大流最小割定理,\(最大流=最小割\),而该图又为一个平面图,可知 \(平面图最短路=流网络最小割\),具体见 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;
}
标签:抽水,容量,int,引水,样例,3246,管道,define
From: https://www.cnblogs.com/zyyun/p/16953668.html