bzoj 4334 铁拳

Description

经过了可怕的第三次世界大战后,国家政府崩溃,各大财团趁机夺取掌控世界。长年战争后,八大财团幸存并割据一方,其中最强的当属掌控北美的铁拳。

在铁拳财团所维护的文明区域中,有一项最为光荣、重要的赛事—— Iron Fist ,也就是铁拳大赛。 IF 中云集了世界各地各财团鼎力资助的世外高手,只为了赢得 IF Champion,得到无上的荣耀,当然还有随之而来的权力。本来一切秩序井然,但一个来自贫民窟的少年风间仁意外地在海选中赢了 IF 正式选手,获得了决赛资格,从此格局被打乱……

为了应对这突如其来的变数,IF 管理层决定先对联盟中所有的选手进行评估,以更好地掌握大局。

已知最近 \(m\) 届比赛出现过的 \(n\) 位选手,背后都有着各自财团的资助,并且签下了合同。由于这是各财团的高度机密,合同的具体细节无从得知,但铁拳财团的间谍们通过各种渠道得知了每个选手的薪金范围(显然薪金是非负数)。

对于最近 \(m\) 届的 IF 比赛(从 \(1\) 开始编号),每一届联盟都会进行清算,通过国际金融手段准确计算出这一届联盟选手身价总和的变化。每一届中,会有一些新选手加入,也会有部分选手在比赛中丧失了战斗能力,而被踢出联盟,流放到贫民窟。

现在给出联盟中 \(n\) 位选手的身价范围,以及他们 进入联盟的届数( \(0\) 表示在 \(m+1\) 届以前就已经是联盟选手) 和 离开联盟的届数( \(0\) 表示是现役选手)。同时给出最近 \(m\) 届中,每一届联盟选手身价总和减去上一届的值。

请你根据现有信息,尽可能准确地给出每个选手可能的薪金范围。各选手之间的薪金范围可以不同时成立,但对于一位选手的范围中的每一个数,都必须至少存在一种合法方案使该选手能得到相应薪金,而且这个范围跨度要尽可能大。

如果输入信息有误,请输出 \(-1\) ,表示无解。

Input

第一行一个正整数 \(m\) ,意义见上(下同)。

第二行包含 \(m\) 个整数,第i个表示第 \(i\) 届中 选手身价总和 的变化情况。

第三行一个正整数 \(n\)

接下来 \(n\) 行,每行包含四个整数,分别表示 身价下限 、 身价上限 、 出道届数 、 退役届数,细节请参照上文。

保证出道时间严格比退役时间小( \(0\) 除外)。

Output

如果输入信息有误,仅输出一行一个整数“-1”(不含双引号)。

否则输出 \(n\) 行,每行两个实数,第 \(i\) 行表示第 \(i\) 个选手实际身价的准确范围。

保留两位小数,需要与标准答案完全相同才得分。

Sample Input

2
5 ‐1
3
1 4 1 0
2 3 1 0
1 5 1 2

Sample Output

1.00 2.00
2.00 3.00
1.00 1.00

HINT

Explanation

第二届只有 \(3\) 号离开了,可以锁定 \(3\) 号的薪金是 \(1\)

如此一来,\(1\) 号和 \(2\) 号薪金之和为 \(4\) ,那么 \(1\) 号最少能拿 \(1\) ,最多能拿 \(2\)\(2\) 号最少能拿到 \(2\) ,最多能拿到 \(3\)

Data

对于 \(100\%\) 的数据, \(n\le 200,m\le 100\) ,给定薪金范围不超过 \(20000\)

Solution

今天下午被 Joker 和 Azrael_Death 教导了好久才开窍。

线性规划,用上下界网络流来做。

翻译一下题:给定 \(n\) 个未知数,以及 \(m\) 条方程,其中未知数系数绝对值为 \(1\) ,保证等式之间没有相同的单项。再给出每个未知数的范围约束。求每个未知数的取值范围。

首先我们假看到这篇博客的人都会上下界网络流。

我们把每个方程看成点,每个未知数看成边。我们把第 \(i\) 个方程的值记作 \(gap_i\),第 \(i\) 个未知数的取值范围、进/出方程位置分别记作 \(lw_i,up_i,L_i,R_i\) 。 显然每个未知数只会进出方程各一次,所以未知数 \(i\) 所表示的边有且仅有一条。

设源、汇、超级源、超级汇分别为 \(SS, TT, S, T\)

对于未知数 \(i\) ,若 \(L_i=0\) 则记 \(u = SS\) ,否则 \(u=L_i\) ;若 \(R_i=0\) 则记 \(v = TT\) ,否则 \(v=R_i\) 。那么我们有 $$ <u,v>:capacity=[lw_i,up_i] $$

对于方程 \(i\) ,若 \(gap_i > 0\) ,则 \(u = SS\)\(v=i\) ;否则 \(u = i\)\(v=TT\) 。我们有 $$ <u,v>:capacity=[|gap_i|,|gap_i|] $$

然后我们尝试跑一个可行流。若没有,直接输出 \(-1\) 。若有,我们将在残量网络上求出答案。考虑每条边可以再多/少承载多少流量。方法是干掉这条边,以起点为源,终点为汇,跑最大流;然后以起点为汇,终点为源,再跑最大流。因为有 \([lw_i,up_i]\) 的限制,所以要处理一下。具体见代码。

#include<bits/stdc++.h> 
using namespace std;

#define N 250
#define INF 2000000000
#define rep(i, a, b) for (int i = a; i <= b; i++)

inline int read() {
	int x = 0, flag = 1; char ch = getchar(); while (!isdigit(ch)) { if (!(ch ^ '-')) flag = -1; ch = getchar(); }
	while (isdigit(ch)) x = (x << 1) + (x << 3) + ch - '0', ch = getchar(); return x * flag;
}

int n, m;
int gap[N], up[N], lw[N], L[N], R[N];
int du[N], mch[N];

int S, T, SS, TT;
struct edge { 
	int v, c, next;
	edge(int _v = 0, int _c = 0, int _next = 0):v(_v), c(_c), next(_next) {}
}e[1001], cpy[1001];
int head[N], tot = 1, tag[1001];
int q[N], dep[N];

inline void insert(int u, int v, int c) { e[++tot] = edge(v, c, head[u]), head[u] = tot; }
inline void add(int u, int v, int c) { insert(u, v, c), insert(v, u, 0); }

inline bool bfs() {
	memset(dep, 0, sizeof dep); dep[S] = 1;
	int l = 1, r = 1; q[1] = S;
	while (l <= r) {
		int u = q[l++];
		for (int i = head[u], v; i; i = e[i].next) if (!tag[i] && e[i].c && !dep[v = e[i].v]) {
			dep[v] = dep[u] + 1, q[++r] = v;
			if (!(v ^ T)) return 1;
		}
	}
	return 0;
}
int dfs(int u, int dist) {
	if (!(u ^ T) || !dist) return dist;
	int ret = 0;
	for (int i = head[u], v, c; i; i = e[i].next) if (!tag[i] && (c = e[i].c) && !(dep[v = e[i].v] ^ (dep[u] + 1))) {
		int d = dfs(v, min(dist, c));
		dist -= d, ret += d, e[i].c -= d, e[i ^ 1].c += d;
		if (!dist) break;
	}
	return ret;
}

inline int dinic() { int ret = 0; while (bfs()) ret += dfs(S, INF); return ret; }

bool getAva() {
	rep(i, 1, m) {
		if (gap[i] > 0) du[SS] -= gap[i], du[i] += gap[i];
		else du[i] += gap[i], du[TT] -= gap[i];
	}
	rep(i, 1, n) {
		int u = L[i] ? L[i] : SS, v = R[i] ? R[i] : TT;
		add(u, v, up[i] - lw[i]), du[u] -= lw[i], du[v] += lw[i], mch[i] = tot - 1;
	}
	add(TT, SS, INF);
	int sum1 = 0, sum2 = 0;
	rep(i, SS, TT) if (du[i] >= 0) add(S, i, du[i]), sum1 += du[i]; else add(i, T, -du[i]), sum2 -= du[i];
	return dinic() == sum1 && sum1 == sum2;
}

inline void reset() { rep(i, 0, tot) e[i] = cpy[i]; }

int main() {
	cin >> m; rep(i, 1, m) gap[i] = read();
	cin >> n; rep(i, 1, n) lw[i] = read(), up[i] = read(), L[i] = read(), R[i] = read();
	TT = m + 1, S = TT + 1, T = S + 1;
	if (!getAva()) { puts("-1"); return 0; }
	rep(i, 0, tot) cpy[i] = e[i];
	rep(i, 1, n) {
		int id = mch[i], t1 = e[id ^ 1].c, t2 = e[id].c + t1; tag[id] = tag[id ^ 1] = 1;
		S = e[id ^ 1].v, T = e[id].v, printf("%d.00 ", lw[i] + max(t1 - dinic(), 0)), reset();
		S = e[id].v, T = e[id ^ 1].v, printf("%d.00\n", lw[i] + min(t1 + dinic(), t2)), reset();
		tag[id] = tag[id ^ 1] = 0;
	}
	return 0;
}
posted @ 2018-02-10 21:52  aziint  阅读(261)  评论(0编辑  收藏  举报
Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.