STEAD - Steady Cow Assignment

首先可以二分答案,接着考虑如何写 check

我们发现尽管我们二分了最大和最小的差,但我们仍然无法确定这个区间,这是因为最小值不固定。

由于 B20B \leq 20,所以我们可以枚举最小值,求出对应区间。也就是说,每头牛去的牛棚在 [i,i+x1][i,i+x-1] 之间,ii 是我们枚举的最小值,xx 是二分的最大值与最小值的差值。

考虑建立网络流模型,容易发现牛和牛棚可以看作二分图。对于每头牛 ii,源点 SiS \rightarrow i,容量为 11,表示每头牛只能去一个牛棚。对于每头牛 ii 和牛能去的牛棚 j(j[i,i+x1])j(j\in [i,i+x-1]),连 iji \rightarrow j,容量为 11,表示每头牛去了一个牛棚,牛棚的牛数增加 11。最后,每个牛棚 jTj \rightarrow T,容量为 cic_i,表示每个牛棚只接受最多 cic_i 头牛。

若最大流 n\geq n,表示存在方案使得 nn 头牛到牛棚且满足二分的限制。

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

const int N = 5e5 + 5;

int e[N], h[N], c[N], ne[N], idx;

int n, b;
vector<int> p[N];
int v[N];
int S, T;

void CLEAR_GRAPH()
{
	for (int i = 0; i <= T; i++) h[i] = -1;
	idx = 0;
}

inline void add(int u, int v, int w)
{
	e[idx] = v, c[idx] = w, ne[idx] = h[u], h[u] = idx++;
	e[idx] = u, c[idx] = 0, ne[idx] = h[v], h[v] = idx++;
}

int d[N], cur[N];

inline bool bfs()
{
	for (int i = 0; i <= T; i++) d[i] = -1, cur[i] = -1;
	queue<int> q;
	q.push(S);
	d[S] = 0, cur[S] = h[S];
	while (q.size())
	{
		int u = q.front();
		q.pop();
		for (int i = h[u]; ~i; i = ne[i])
		{
			int j = e[i];
			if (c[i] > 0 && d[j] == -1)
			{
				d[j] = d[u] + 1;
				cur[j] = h[j];
				if (j == T) return 1;
				q.push(j);
			}
		}
	}
	return 0;
}

inline int dfs(int u, int lim)
{
	if (u == T) return lim;
	int sum = 0;
	for (int i = cur[u]; ~i && sum < lim; i = ne[i])
	{
		cur[u] = i;
		int j = e[i];
		if (c[i] > 0 && d[j] == d[u] + 1)
		{
			int p = dfs(j, min(c[i], lim - sum));
			if (!p) d[j] = -1;
			else
			{
				sum += p;
				c[i] -= p;
				c[i ^ 1] += p;
			}
		}
	}
	return sum;
}

inline int dinic()
{
	int res = 0;
	while (bfs())
	{
		int p;
		while (p = dfs(S, INT_MAX)) res += p;
	}
	return res;
}

bool check(int x)
{
	CLEAR_GRAPH();
	for (int i = 0; i + x - 1 < p[1].size(); i++)
	{
		CLEAR_GRAPH();
		for (int j = 1; j <= n; j++)
		{
			add(S, j, 1);
			for (int k = i; k <= i + x - 1; k++)
			{
				add(j, p[j][k] + n, 1);
			}
		}
		for (int j = 1; j <= b; j++)
		{
			add(j + n, T, v[j]);
		}
		int g = dinic();
		if (g >= n) return 1;
	}
	return 0;
}

int main()
{
	scanf("%d%d", &n, &b);
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= b; j++)
		{
			int x;
			scanf("%d", &x);
			p[i].emplace_back(x);
		}
	}
	for (int i = 1; i <= b; i++)
	{
		scanf("%d", &v[i]);
	}
	T = n + b + 1;
	int l = 0, r = b, ans = -1;
	while (l <= r)
	{
		int mid = l + r >> 1;
		if (check(mid)) ans = mid, r = mid - 1;
		else l = mid + 1;
	}
	printf("%d\n", ans);
	return 0;
}
posted @   HappyBobb  阅读(3)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示