【题目大意】
给一张网格图,上往下有流量限制,下往上没有,左往右有流量限制。
$n * m \leq 2.5 * 10^6$
【题解】
考场直接上最大流,50分。竟然傻逼没看出狼抓兔子。
平面图转对偶图,其中没有流量限制(inf)不用转,然后直接在DAG上分层dp即可。
复杂度$O(nm)$,但是这样过不去被卡常了。
出题人的做法是先处理出每层初始的那个随机数,然后每层往下直接做,这样因为是一维数组,所以寻址方便,不会被卡常。
我的做法是动态开数组(用new),然后比较两维大小来分配第一维给谁,第一维优先分配给小的,第二维给大的。
然后如果n >= m可以用指针优化,所以阈值设为n * 10 >= m即可(虽然没啥必要)
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
# include <stdio.h> # include <string.h> # include <iostream> # include <algorithm> // # include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int M = 2.5e5 + 10; const int mod = 1e9+7; namespace irand { int A, B, Q, X0; inline void getseed() { cin >> A >> B >> Q >> X0; } inline int getint() { return X0 = (1ll * A * X0 + B) % Q; } } int n, m, **ad, **bd; ll f[M]; int main() { cin >> n >> m; irand :: getseed(); if(n * 10 >= m) { ad = new int*[m + 5]; bd = new int*[m + 5]; --n; for (register int i=1; i<=m; ++i) ad[i] = new int[n + 5], bd[i] = new int[n + 5]; for (register int i=1; i<=n; ++i) for (register int j=1; j<=m; ++j) ad[j][i] = irand :: getint(); for (register int i=1; i<n; ++i) for (register int j=1; j<m; ++j) bd[j][i] = irand :: getint(); for (register int i=1; i<m; ++i) { register int *A = ad[i], *B = bd[i]; for (register int j=1; j<=n; ++j) f[j] += A[j]; for (register int j=2; j<=n; ++j) f[j] = min(f[j], f[j-1]+B[j-1]); for (register int j=n-1; j; --j) f[j] = min(f[j], f[j+1]+B[j]); } ll ans = 1e18; for (int i=1; i<=n; ++i) f[i] += ad[m][i]; for (int i=1; i<=n; ++i) ans = min(ans, f[i]); cout << ans << endl; return 0; } else { ad = new int*[n + 5]; bd = new int*[n + 5]; --n; for (register int i=1; i<=n; ++i) ad[i] = new int[m + 5], bd[i] = new int[m + 5]; for (register int i=1; i<=n; ++i) for (register int j=1; j<=m; ++j) ad[i][j] = irand :: getint(); for (register int i=1; i<n; ++i) for (register int j=1; j<m; ++j) bd[i][j] = irand :: getint(); for (register int i=1; i<m; ++i) { for (register int j=1; j<=n; ++j) f[j] += ad[j][i]; for (register int j=2; j<=n; ++j) f[j] = min(f[j], f[j-1]+bd[j-1][i]); for (register int j=n-1; j; --j) f[j] = min(f[j], f[j+1]+bd[j][i]); } ll ans = 1e18; for (int i=1; i<=n; ++i) f[i] += ad[i][m]; for (int i=1; i<=n; ++i) ans = min(ans, f[i]); cout << ans << endl; return 0; } }