Loading

省选训练赛 #18 题目 D 补题记录

题意:有 \(n\) 棵待种的植物,关系呈一张 DAG,其中边 \((u, v)\) 表示必须等植物 \(u\) 成熟之后才能种下植物 \(v\),第 \(i\) 棵植物种下后需要花费 \(t_i\) 时间成熟。你有 \(m\) 点魔法,可以使用 \(d_i\) 点魔法令 \(t_i\) 减一,可以多次对一棵植物使用魔法,求最终种完所有植物的最早时间。

\(n, |E|\le 50,\ m,d_i\le 10^9,\ t_i \le 25\)

添加一个源植物 \(s\) 和一个汇植物 \(t\),前者需要种下后才能种其他植物,后者必须在所有植物种完后才能种下。设 \(x_i, y_i\) 表示植物 \(i\) 的种下时刻和成熟时刻,设 \(p_i\) 表示植物 \(i\) 的施法次数。二分答案 \(mid\),那么应该满足:

  • \(y_s + mid \ge x_t\)

  • \(x_i \le y_i\)

  • \(x_i + t_i - d_i \le y_i\)

  • \(x_v \ge y_u , \ \forall (u, v) \in E\)

不难发现这是最小费用循环流的对偶形式(详见此处):

  • \(0 - x_t + y_s \ge -mid\)

  • \(0 - x_i + y_i \ge 0\)

  • \(d_i - x_i + y_i \ge t_i\)

  • \(0 - y_u + x_v \ge 0, \ \forall (u, v) \in E\)

但是某些 \(d_{u, v}\) 必须取 \(0\),考虑答案式子 \(\sum_{(u, v) \in E} w_{u, v}d_{u, v}\) 中,令 \(w_{u, v} = + \infty\) 即可。

点击查看代码
#include <bits/stdc++.h>

namespace Initial {
	#define ll long long
	#define ull unsigned long long
	#define fi first
	#define se second
	#define mkp make_pair
	#define pir pair <ll, ll>
	#define pb push_back
	#define i128 __int128
	using namespace std;
	const ll maxn = 1050, inf = 1e13, mod = 1e9 + 7, L = 1e7 + 10;
	ll power(ll a, ll b = mod - 2, ll p = mod) {
		ll s = 1;
		while(b) {
			if(b & 1) s = 1ll * s * a %p;
			a = 1ll * a * a %p, b >>= 1;
		} return s;
	}
	template <class T>
	const inline ll pls(const T x, const T y) { return x + y >= mod? x + y - mod : x + y; }
	template <class T>
	const inline void add(T &x, const T y) { x = x + y >= mod? x + y - mod : x + y; }
	template <class T>
	const inline void chkmax(T &x, const T y) { x = x < y? y : x; }
	template <class T>
	const inline void chkmin(T &x, const T y) { x = x > y? y : x; }
} using namespace Initial;

namespace Read {
	char buf[1 << 22], *p1, *p2;
	// #define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, (1 << 22) - 10, stdin), p1 == p2)? EOF : *p1++)
	template <class T>
	const inline void rd(T &x) {
		char ch; bool neg = 0;
		while(!isdigit(ch = getchar()))
			if(ch == '-') neg = 1;
		x = ch - '0';
		while(isdigit(ch = getchar()))
			x = (x << 1) + (x << 3) + ch - '0';
		if(neg) x = -x;
	}
} using Read::rd;

ll n, t[maxn], c[maxn], a[maxn][maxn], m, deg[maxn], sum;
char str[maxn][maxn];

struct Graph {
	ll n, s, t, head[maxn], tot, cur[maxn];
	struct edge {ll v, w, c, nxt;} e[maxn];
	void ins(ll u, ll v, ll w, ll c) {
		e[++tot] = (edge) {v, w, c, head[u]}, head[u] = tot;
		e[++tot] = (edge) {u, 0, -c, head[v]}, head[v] = tot;
	}
	bool vis[maxn]; ll dis[maxn]; queue <ll> q;
	bool spfa() {
		for(ll i = 1; i <= n; i++) dis[i] = inf;
		dis[s] = 0, q.push(s);
		while(!q.empty()) {
			ll u = q.front(); q.pop(), vis[u] = false;
			for(ll i = head[u]; i; i = e[i].nxt) {
				ll v = e[i].v, w = e[i].w, c = e[i].c;
				if(w && dis[v] > dis[u] + c) {
					dis[v] = dis[u] + c;
					if(!vis[v])
						vis[v] = true, q.push(v);
				}
			}
		} return dis[t] < inf;
	}
	ll dfs(ll u, ll flow) {
		if(u == t) return flow;
		ll used = 0; vis[u] = true;
		for(ll i = cur[u]; i; cur[u] = i = e[i].nxt) {
			ll v = e[i].v, w = e[i].w, c = e[i].c;
			if(!vis[v] && w && dis[v] == dis[u] + c) {
				ll tmp = dfs(v, min(w, flow - used));
				used += tmp, e[i].w -= tmp, e[i ^ 1].w += tmp;
				if(used == flow) break;
			}
		} vis[u] = false; return used;
	}
	pir dinic() {
		ll f = 0, c = 0;
		while(spfa()) {
			for(ll i = 1; i <= n; i++) cur[i] = head[i];
			f += dfs(s, inf);
		}
		for(ll i = 3; i <= tot; i += 2) c -= e[i].w * e[i].c;
		return mkp(f, c);
	}
	void clr() {
		for(ll i = 1; i <= n; i++) head[i] = 0;
		tot = 1, n = s = t = 0;
	}
} G;

bool check(ll mid) {
	G.clr(), G.ins(2 * n + 3, n + 2, inf, mid); sum = 0;
	for(ll i = 1; i <= 2 * n + 4; i++) deg[i] = 0;
	for(ll i = 1; i <= n; i++) {
		G.ins(i + n + 2, i, inf, 0), G.ins(i, i + n + 2, c[i], t[i]);
		deg[i + n + 2] += c[i], deg[i] -= c[i];
		sum += c[i] * t[i];
	}
	for(ll i = 1; i <= n; i++)
		G.ins(i, 2 * n + 3, inf, 0), G.ins(n + 2, i + n + 2, inf, 0);
	for(ll u = 1; u <= n; u++)
		for(ll v = 1; v <= n; v++)
			if(a[u][v]) G.ins(v, u + n + 2, inf, 0);
	ll S = 2 * n + 5, T = S + 1, g = 0;
	G.n = G.t = T, G.s = S;
	for(ll i = 1; i <= 2 * n + 4; i++)
		if(deg[i] < 0) G.ins(S, i, -deg[i], 0), g -= deg[i];
		else if(deg[i] > 0) G.ins(i, T, deg[i], 0);
	pir res = G.dinic();
	return res.fi == g && sum - res.se <= m;
}

int main() {
	rd(n);
	for(ll i = 1; i <= n; i++) {
		scanf("%s", str[i] + 1);
		for(ll j = 1; j <= n; j++)
			if(str[i][j] == '1') a[j][i] = 1;
	} rd(n);
	for(ll i = 1; i <= n; i++) rd(t[i]);
	rd(n);
	for(ll i = 1; i <= n; i++) rd(c[i]);
	rd(m);
	ll lo = 0, hi = 1250;
	while(lo <= hi) {
		ll mid = lo + hi >> 1;
		if(check(mid)) hi = mid - 1;
		else lo = mid + 1;
	} printf("%lld\n", lo);
	return 0;
}
posted @ 2025-01-07 19:37  Lgx_Q  阅读(2)  评论(0编辑  收藏  举报