3246. 引水入城

题目链接

3246. 引水入城

MF 城建立在一片高原上。

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

如下图所示:

image

这片管网由 \(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\) 组评测数据,每组数据的参数规模如下所示:

image

输入样例1:

3 3 10 3 19 7

输出样例1:

38

样例1解释

使用参数得到数列 \(\{ X_i \}=\{ 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\) 和 汇点 \(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;
}
posted @ 2022-12-05 21:50  zyy2001  阅读(39)  评论(0编辑  收藏  举报