首页 > 其他分享 >【YBT2023寒假Day1 A】孤走暗巷(费用流)

【YBT2023寒假Day1 A】孤走暗巷(费用流)

时间:2023-01-28 21:01:07浏览次数:56  
标签:return KK ll YBT2023 Day1 暗巷 go now dis

孤走暗巷

题目链接:YBT2023寒假Day1 A

题目大意

给你一个整数序列,你要通过一些操作把它变成单调不降序列。
你有 m 种操作,每次可以选择一个长度为 li 的区间,花费 ci 的代价将其加一或减一(是加一还是减一看给你的操作),问你最小代价,或者输出无解。

思路

首先这个区间加减不难想到通过差分变成某两个位置分别加一减一。
然后发现变成单调不降就是中间的部分都是要非 \(0\) 数。

看到 \(n,m\) 都很小,而且 DP 似乎不太可行(因为有两个位置同时修改),考虑费用流。
然后因为两个位置同时修改的都是 \(1\) 的绝对值,而且是相反数,你可以理解为把这个 \(1\) 交给了另一个位置。
那你在思考一开始的正负,会发现正的就是它可以给出的最大数量,负的就是它需要的最小数量。
然后因为两边的正负是无所谓的,也就是它可以给出无限的数量。

那我们就把正的跟源点连,负的跟汇点连,两边就是跟源点连流量无限大,都是费用 \(0\)。
然后再模拟给的操作思考会发现是给的流向收到的,然后连边流量无限费用是给出的值。
不过要注意的是它只是限制的区间的长度,所以你可以直接从左往右滑动那个区间,每个都要连边,边数是 \(O(nm)\) 级别没问题。

至于判断是否有解,其实就是看是否刘曼,然后因为源点那边有无限流量的边,我们判断汇点那边的边就行。

代码

#include<queue>
#include<cstdio>
#include<iostream>
#define ll long long
#define INF 0x3f3f3f3f3f3f3f3f

using namespace std;

const int N = 250;
const int M = N * N * 20;
const int inf = 1e8;
struct node {
	ll x, w, to, nxt, op;
}e[M];
ll n, m, S, T, tot, le[M], lee[M], KK;
ll dis[M], deg[M], h[N], p[N];
bool in[M];
queue <ll> q;

void add(ll x, ll y, ll z, ll w) {
	e[++KK] = (node){z, w, y, le[x], KK + 1}; le[x] = KK;
	e[++KK] = (node){0, -w, x, le[y], KK - 1}; le[y] = KK;
}

bool SPFA() {
	for (ll i = 0; i <= tot; i++) {
		dis[i] = INF;
		in[i] = 0;
		deg[i] = -1;
		lee[i] = le[i];
	}
	while (!q.empty()) q.pop();
	
	q.push(S);
	dis[S] = 0;
	in[S] = 1;
	deg[S] = 0;
	while (!q.empty()) {
		ll now = q.front();
		q.pop();
		
		for (ll i = le[now]; i; i = e[i].nxt)
			if (e[i].x > 0 && dis[e[i].to] > dis[now] + e[i].w) {
				dis[e[i].to] = dis[now] + e[i].w;
				deg[e[i].to] = deg[now] + 1;
				if (!in[e[i].to]) {
					in[e[i].to] = 1;
					q.push(e[i].to);
				}
			}
		
		in[now] = 0;
	}
	
	if (dis[T] == dis[0]) return 0;
	return 1;
}

ll dfs(ll now, ll sum) {
	if (now == T) return sum;
	in[now] = 1;
	ll go = 0;
	for (ll &i = lee[now]; i; i = e[i].nxt)
		if (!in[e[i].to] && e[i].x > 0 && dis[e[i].to] == dis[now] + e[i].w && deg[e[i].to] == deg[now] + 1) {
			ll this_go = dfs(e[i].to, min(sum - go, e[i].x));
			if (this_go) {
				e[i].x -= this_go;
				e[e[i].op].x += this_go;
				go += this_go;
				if (go == sum) return go;
			}
		}
	if (go == sum) in[now] = 0;
	return go;
}

ll dinic_cost() {
	ll re = 0;
	while (SPFA()) {
		re += dis[T] * dfs(S, INF);
	}
	return re;
}

int main() {
	freopen("seq.in", "r", stdin);
	freopen("seq.out", "w", stdout);
	
	scanf("%lld %lld", &n, &m);
	for (int i = 1; i <= n; i++) scanf("%lld", &h[i]);
	for (int i = 1; i <= n + 1; i++) p[i] = h[i] - h[i - 1];
	
	S = n + 2;
	T = n + 3;
	tot = T;
	
	for (int i = 1; i <= n + 1; i++) {
		if (i == 1 || i == n + 1) add(S, i, inf, 0);
			else if (p[i] > 0) add(S, i, p[i], 0);
				else if (p[i] < 0) add(i, T, -p[i], 0);
	}
	for (int i = 1; i <= m; i++) {
		char op = getchar(); while (op != '+' && op != '-') op = getchar();
		int l, c; scanf("%d %d", &l, &c); if (l == n) continue;
		for (int j = 1; j + l <= n + 1; j++) {
			if (op == '-') add(j, j + l, inf, c);
				else add(j + l, j, inf, c);
		}
	}
	
	ll ans = dinic_cost();
	for (int i = le[T]; i; i = e[i].nxt) {
		if (e[e[i].op].x) {
			printf("-1"); return 0;
		}
	}
	printf("%lld", ans);
	
	return 0;
}


标签:return,KK,ll,YBT2023,Day1,暗巷,go,now,dis
From: https://www.cnblogs.com/Sakura-TJH/p/YBT2023Day1_A.html

相关文章

  • 《RPC实战与核心原理》学习笔记Day11
    13|优雅关闭:如何避免服务停机带来的业务损失?我们在RPC架构下,需要考虑当服务重启时,如何做到让调用方系统不出问题。当服务提供方要上线时,一般是通过部署系统完成实例重......
  • 「WC-2023」学习笔记(Day1&2)
    尼玛在游记里立flag是吧。1月必更新是吧。寒假作业都写不完了!!!!!这篇四舍五入就是1月学习记录了。1月剩下的杂题可能放2月去写。嗯也可能2月就退役了。退役了就没......
  • day11-实现Spring底层机制-01
    实现Spring底层机制-01主要实现:初始化IOC容器+依赖注入+BeanPostProcessor机制+AOP前面我们实际上已经使用代码简单实现了:SpringXML注入bean(Spring基本介绍02)Sp......
  • C++Day13 tinyxml2解析rss文件
    一、任务与思路使用tinyxml解析rss文件,使用std::regex(正则表达式)去除html标签,并生成一个pagelib.txt,格式如下<doc><docid>1</docid><title>...</title><......
  • PLC笔记 知识点汇总 day1
          blog:师万物 本文是学习内容的简单回顾,希望对大家能有所帮助。 电路直流蓄电池交流单相(两线、三相)、两相、三相(三线、四线、五线)发电机:......
  • 《RPC实战与核心原理》学习笔记Day10
    11|负载均衡:节点负载差距这么大,为什么收到的流量还一样?什么是负载均衡?当我们的一个服务节点无法支撑现有的访问量时,我们会部署多个节点,组成一个集群,然后通过负载均衡,......
  • day12
    1、leetcode239滑动窗口最大值思路:使用一个队列,将窗口里的元素放入队列,然后随着窗口的移动,队列也一进一出,每次移动之后,队列告诉我们里面的最大值是什么。队列所需......
  • Day19 - 正则表达式
    正则表达式的概述正则表达式的介绍在实际开发过程中经常会有查找符合某些复杂规则的字符串的需要,比如:邮箱、图片地址、手机号码等,这时候想匹配或者查找符合某些规则的......
  • Day18 - property和拷贝
    1.装饰器方式的property使用@property对get方法进行装饰get方法在装饰时,不需要再以get_做为前缀在通过@property装饰好Get方法后,可以使用get方法的方法......
  • Day17 - mini-Web框架
    1.web框架概述web框架和web服务器的关系介绍前面已经学习过web服务器,我们知道web服务器主要是接收用户的http请求,根据用户的请求返回不同的资源数据,但是之前我们开......