The 2019 ICPC Asia Shanghai Regional Contest (replay) M-Blood Pressure Game (cost flow & calculation contribution)

Link: https://ac.nowcoder.com/acm/contest/4370/M
Source: Niuke
 

Title description

1Gugulu, a JBer, who was an ACMer one year ago, comes to Shanghai University taking part in the International Collegiate Programming Contest again. However, every time when Gugulu came to Shanghai University, he always got an Iron Medal and would consider this competition JB-like. To release his pain, Gugulu would go to the Shanghai Disneyland Park to have fun in taking the Roller Coaster. Gugulu loves the feeling with high-level blood pressure so much which makes him feel as a happy flappy bird who forgets all the Wrong Answers and Time Limit Exceededs etc.

We can regard the path of the Roller Coaster as a list of turning points with different heights which can be represented as an array {a1,a2,a3,…,an}\{a_1, a_2, a_3, …, a_n\}{a1​,a2​,a3​,…,an​} of size n{n}n, and Gugulu's final blood pressure after the game of the Roller Coaster is counted as the sum of all absolute values of the differences between the n−1{n - 1}n−1 pairs of adjacent array numbers, i.e. ∑i=1n−1∣ai−ai+1∣\displaystyle \sum_{i=1}^{n-1} \left| a_i - a_{i+1} \right|i=1∑n−1​∣ai​−ai+1​∣.

Gugulu always got Iron Medals and is always getting Iron Medals, which makes him keep taking the Roller Coaster over and over again. However, as playing more games, his threshold on the value of blood pressure which can make himself happy is keeping increasing. As a result, the Roller Coaster of Shanghai Disneyland Park can hardly meet Gugulu's need anymore.

Therefore, Gugulu decides to add a set of m extra turning points in any order into this path, however, to consider about the reality on the distance of the original path, he can add at most one turning point into any original position between any two original elements in the array (and at most one in the head, at most one in the tail). Gugulu wants to make his blood pressure as high as possible, and he wants to know how much his blood can reach at most when he has added {1,2,3,…,m}{\{1, 2, 3, …, m\}}{1,2,3,…,m} nextra Roller Coaster turning points into the path.

You, another JBer, are sure that Gugulu is clever enough to get the highest blood pressure as he can. It is very important for you to calculate the exact numbers to make an appointment with a proper cardiologist in advance to save Gugulu's life. You must solve this problem! Gugulu's blood pressure is becoming out of the control!

Enter description:

The first line of the input gives the number of test cases, T\mathbf{T}T (1≤T≤10001 \leq \mathbf{T} \leq 10001≤T≤1000). T\mathbf{T}T test cases follow.
For each test case, the first line contains two integers, n{n}n (1≤n≤6001 \leq n \leq 6001≤n≤600) and m{m}m (1≤m≤n+11 \leq m \leq n+11≤m≤n+1) 
Then, in second line, there are n{n}n integers {a1,a2,a3,…,an}\{a_1, a_2, a_3, …, a_n\}{a1​,a2​,a3​,…,an​} (1≤ai≤109)(1 \leq a_i \leq 10^9)(1≤ai​≤109), denoting the n{n}n original Roller Coaster turning points. Then, in the third line, there are m{m}m integers {b1,b2,b3,…,bm}\{b_1, b_2, b_3, …, b_m\}{b1​,b2​,b3​,…,bm​} (1≤bi≤109)(1 \leq b_i \leq 10^9)(1≤bi​≤109), denoting the m{m}m addition Roller Coaster turning points to be added. 
As it is an exciting Roller Coaster, it is guaranteed that all n+m{n + m}n+m integers in the two arrays are pairwise different.
There are at most 10{10}10 test cases whose n{n}n is more than 100{100}100.

Output description:

For each test case, output three lines. The first line contains "Case #x:", where x{x}x is the test case number (starting from 1{1}1). In the second line, there should be m{m}m integers which represent how much Gugulu's blood pressure could reach if he has added {1, 2, 3, …, m} extra Roller Coaster turning points into the path. In the third line, there should be n+m{n + m}n+m integers which represent the heights of the final Roller Coaster path if he has added all m{m}m extra  turning points. If there are several solutions, output any of them.

Example 1

enter

Copy 6 2 3 5 11 10 3 1 4 1 1 2 3 4 5 4 2 1 2 3 4 5 6 4 5 1 2 3 4 5 6 7 8 9 4 4 10 50 3 6 1 9 23 5 4 2 10 50 3 6 9 23

6
2 3
5 11
10 3 1
4 1
1 2 3 4
5
4 2
1 2 3 4
5 6
4 5
1 2 3 4
5 6 7 8 9
4 4
10 50 3 6
1 9 23 5
4 2
10 50 3 6
9 23

Output

复制Case #1: 16 22 27 10 5 1 11 3 Case #2: 9 1 5 2 3 4 Case #3: 11 15 1 6 2 5 3 4 Case #4: 17 27 33 38 39 5 1 9 2 8 3 7 4 6 Case #5: 124 142 147 150 5 10 1 50 3 23 6 9 Case #6: 124 127 10 50 3 23 6 9

Case #1:
16 22 27 
10 5 1 11 3 
Case #2:
9 
1 5 2 3 4 
Case #3:
11 15 
1 6 2 5 3 4 
Case #4:
17 27 33 38 39 
5 1 9 2 8 3 7 4 6 
Case #5:
124 142 147 150 
5 10 1 50 3 23 6 9 
Case #6:
124 127 
10 50 3 23 6 9

Main idea:

Give you a sequence of length N and a sequence of length M. You need to insert these M numbers into the first sequence. Only one number can be inserted between the two numbers (it can be placed on the left or right) , The order of insertion is arbitrary, and the weight of the sequence is the sum of the absolute value of the difference between adjacent numbers. Output the M numbers in the first row, the i-th number represents the maximum weight value after inserting the i numbers, and the second line output the sequence of the maximum weight value after inserting the M numbers.

solution:

There are N+1 points that can be connected to M numbers, corresponding to N+1 positions that can be inserted. First, calculate the weight of the initial sequence. When a point is inserted, its contribution is the weight after the insertion-the original Weight, so the mapping method is: the source point is connected to M points, the flow is 1, the cost is 0, the M points are connected to N+1 points, the flow is 1, the cost is the contribution, and N+1 points are connected to the sink Point, the flow is 1, the cost is 0, and the maximum cost flow is run M times, and finally the sequence is output in the residual network.

This question was issued by a team of our school's big guys (under the premise of knowing that it is a network stream), and the ideas are all learned from him, I am still too good QAQ

 Accetped code

#pragma GCC optimize(3)
#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;

#define sc scanf
#define ls rt << 1
#define rs ls | 1
#define Min(x, y) x = min(x, y)
#define Max(x, y) x = max(x, y)
#define ALL(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define pir pair <int, int>
#define MK(x, y) make_pair(x, y)
#define MEM(x, b) memset(x, b, sizeof(x))
#define MPY(x, b) memcpy(x, b, sizeof(x))
#define lowbit(x) ((x) & -(x))
#define P2(x) ((x) * (x))

typedef long long ll;
const int Mod = 1e9 + 7;
const int N = 1210;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
inline ll dpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t) % Mod; b >>= 1; t = (t*t) % Mod; }return r; }
inline ll fpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t); b >>= 1; t = (t*t); }return r; }

struct Edge
{
	ll f, w;
	int r, v;
};
vector <Edge> G[N];
ll dis[N], flow[N];
ll mxflow, mxcost;
int n, m, sp, tp;
int pre[N], lst[N];
bool vis[N];
int a[N], b[N];

void Init() {
	sp = 0, tp = n + m + 2;
	for (int i = sp; i <= tp; i++)
		G[i].clear();
	mxflow = mxcost = 0;
}
void Add(int u, int v, ll f, ll w) {
	G[u].push_back({ f, w, SZ(G[v]), v });
	G[v].push_back({ 0, -w, SZ(G[u]) - 1, u });
}
bool Spfa() {   // 找到一条长短路的增广
	queue <int> q;
	for (int i = sp; i <= tp; i++) {
		dis[i] = -LINF;
		flow[i] = LINF;
		vis[i] = false;
	}
	q.push(sp);
	vis[sp] = true;
	dis[sp] = 0, pre[tp] = -1;

	while (!q.empty()) {
		int u = q.front();
		q.pop();
		vis[u] = false;

		for (int i = 0; i < SZ(G[u]); i++) {
			ll f = G[u][i].f, w = G[u][i].w;
			int v = G[u][i].v;
			if (f && dis[v] < dis[u] + w) {
				dis[v] = dis[u] + w;
				pre[v] = u;       // 前驱点
				lst[v] = i;       // 当前边的vector下标
				flow[v] = min(flow[u], f);
				if (!vis[v]) {
					vis[v] = true;
					q.push(v);
				}
			}
		}
	}
	return pre[tp] != -1;
}

int main()
{
	int T;
	cin >> T;
	for (int Case = 1; Case <= T; Case++) {
		sc("%d %d", &n, &m);
		Init();

		ll ans = 0;
		for (int i = 1; i <= n; i++) {
			sc("%d", &a[i]);
			if (i > 1)
				ans += abs(a[i] - a[i - 1]);
		}

		// 源点->待插入点
		for (int i = 1; i <= m; i++) {
			sc("%d", &b[i]);
			Add(sp, i, 1, 0);
		}

		// 待插入点对原序列的贡献
		for (int i = 1; i <= m; i++) {
			for (int j = 1; j <= n + 1; j++) {
				ll w;
				if (j == 1)
					w = abs(b[i] - a[1]);
				else if (j == n + 1)
					w = abs(b[i] - a[n]);
				else
					w = abs(b[i] - a[j - 1]) + abs(b[i] - a[j]) - abs(a[j] - a[j - 1]);
				// 待插入->原序列
				Add(i, m + j, 1, w);
			}
		}

		// 原序列->汇点
		for (int i = 1; i <= n + 1; i++)
			Add(m + i, tp, 1, 0);

		printf("Case #%d:\n", Case);
		for (int i = 1; i <= m; i++) {
			Spfa();
			int now = tp;
			mxflow = flow[tp];
			mxcost = flow[tp] * dis[tp];
			while (now != sp) {
				G[pre[now]][lst[now]].f -= mxflow;
				G[now][G[pre[now]][lst[now]].r].f += mxflow;
				now = pre[now];
			}
			ans += mxcost;
			printf("%lld ", ans);
		}
		puts("");


		for (int i = m + 1; i <= n + m + 1; i++) {
			for (auto it : G[i]) {
				int v = it.v;
				if (v >= 1 && v <= m && it.f) {
					printf("%d ", b[v]);
					break;
				}
			}
			if (i == n + m + 1)
				puts("");
			else
				printf("%d ", a[i - m]);
		}
	}
	return 0;  // 改数组大小!!!用pair记得改宏定义!!!
}

 

Guess you like

Origin blog.csdn.net/weixin_43851525/article/details/107606512