Live2D

Solution -「UR #2」「UOJ #32」跳蚤公路

Description

  Link.

  给定一个 n 个点 m 条边的带权有向图,每条边还有属性 s{1,0,1}。对于每个 u[1,n],求有多少个 xZ,使得图上所有属性为 1 的边权 x,为 0 的不变,为 1+x 后,从 1 走到 u 的任意路径不经过负环。若存在无穷个 x,输出 1

  n100m104

Solution

  可以发现,对于任意初始权和为 b 的简单环,设其上 usu=k,则简单环的最终权值为 kx+b,是一个一次函数,我们需要保证它非负。

  难免涉及到找负环,首先排除 SPFA,我们可以利用 Bellman-Ford 找负环:令 f(i,u) 表示从起点走 i 步到达 u 的最短路,若 f(n1,u)f(n,u),则 uu 可达的点都受负环影响。

  扩展到本题,我们需要记录 k,那么令 f(i,u,k) 表示从起点走 i 步到达 u,经过边的属性和为 k 的最短路,这个表可以暴力 O(n2m) 刷出来。对于一个确定的 x,若 u 被负环影响,联系上面二维情况下的式子,就有:

minj{f(n1,u,j)+jx}mink{f(n,u,k)+kx}

  枚举 j,k,若 j<k,可以得到一个 x 的限制:

xf(n1,u,j)f(n,u,k)kj

  其余情况类似。这样对于每个结点,我们可以求出关于其的若干限制区间 (l,r),表示合法的 x(l,r)。求答案时,枚举每个点 u 和其可达的点 v,求 v 上限制的交集即可。

Code

#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>

typedef long long LL;
typedef std::pair<LL, LL> pll;

inline char fgc () {
	static char buf[1 << 17], *p = buf, *q = buf;
	return p == q && ( q = buf + fread ( p = buf, 1, 1 << 17, stdin ), p == q ) ? EOF : *p ++;
}

inline int rint () {
	int x = 0, f = 1; char s = fgc ();
	for ( ; s < '0' || '9' < s; s = fgc () ) f = s == '-' ? -f : f;
	for ( ; '0' <= s && s <= '9'; s = fgc () ) x = x * 10 + ( s ^ '0' );
	return x * f;
}

inline void wint ( LL x ) {
	if ( x < 0 ) putchar ( '-' ), x = -x;
	if ( 9 < x ) wint ( x / 10 );
	putchar ( x % 10 ^ '0' );
}

const int MAXN = 100, MAXM = 1e4;
const LL INF = 0x3f3f3f3f3f3f3f3f;
int n, m;
LL pool[MAXN + 5][MAXN + 5][MAXN * 2 + 5];
bool rch[MAXN + 5][MAXN + 5];
std::vector<pll> restr[MAXN + 5], inter;

struct Edge {
	int u, v, w, s;
} eset[MAXM + 5];

inline void chkmin ( LL& a, const LL b ) { if ( b < a ) a = b; }
inline void chkmax ( LL& a, const LL b ) { if ( a < b ) a = b; }

inline LL& f ( const int i, const int j, const int k ) { return pool[i][j][k + n + 2]; }

int main () {
	// freopen ( "city.in", "r", stdin );
	// freopen ( "city.out", "w", stdout );
	n = rint (), m = rint ();
	for ( int i = 1; i <= n; ++ i ) rch[i][i] = true;
	for ( int i = 1, u, v, w, s; i <= m; ++ i ) {
		u = rint (), v = rint (), w = rint (), s = rint ();
		eset[i].u = u, eset[i].v = v, eset[i].w = w, eset[i].s = s;
		rch[u][v] = true;
	}
	for ( int k = 1; k <= n; ++ k ) {
		for ( int i = 1; i <= n; ++ i ) {
			for ( int j = 1; j <= n; ++ j ) {
				rch[i][j] |= rch[i][k] && rch[k][j];
			}
		}
	}
	for ( int j = 1; j <= n; ++ j ) {
		for ( int k = -n; k <= n; ++ k ) {
			f ( 0, j, k ) = INF;
		}
	}
	f ( 0, 1, 0 ) = 0;
	for ( int i = 1; i <= n; ++ i ) {
		for ( int j = 1; j <= n; ++ j ) {
			for ( int k = -n; k <= n; ++ k ) {
				f ( i, j, k ) = f ( i - 1, j, k );
			}
		}
		for ( int j = 1; j <= m; ++ j ) {
			int u = eset[j].u, v = eset[j].v, w = eset[j].w, s = eset[j].s;
			for ( int k = -n; k <= n; ++ k ) {
				if ( f ( i - 1, u, k ) == INF ) continue;
				chkmin ( f ( i, v, k + s ), f ( i - 1, u, k ) + w );
			}
		}
	}
	for ( int i = 1; i <= n; ++ i ) {
		for ( int k = -n; k <= n; ++ k ) {
			if ( f ( n, i, k ) >= f ( n - 1, i, k ) ) continue;
			LL l = -INF, r = INF; // x\in(-INF,l]+[r,INF).
			for ( int j = -n; j <= n; ++ j ) {
				if ( j == k || f ( n - 1, i, j ) == INF ) continue;
				if ( j < k ) {
					chkmin ( r, ceil ( 1.0 * ( f ( n - 1, i, j ) - f ( n, i, k ) ) / ( k - j ) ) );
				} else {
					chkmax ( l, floor ( 1.0 * ( f ( n - 1, i, j ) - f ( n, i, k ) ) / ( k - j ) ) );
				}
			}
			if ( l < r ) restr[i].push_back ( pll ( l, r ) );
		}
	}
	for ( int i = 1; i <= n; ++ i ) {
		inter.clear ();
		for ( int j = 1; j <= n; ++ j ) {
			if ( rch[1][j] && rch[j][i] ) {
				for ( int k = 0; k ^ restr[j].size (); ++ k ) {
					inter.push_back ( restr[j][k] );
				}
			}
		}
		if ( inter.empty () ) { puts ( "-1" ); continue; }
		std::sort ( inter.begin (), inter.end () );
		LL l = INF, r = -INF, las = -INF; bool found = false;
		for ( int j = 0; j ^ inter.size (); ++ j ) {
			if ( !j && inter[j].first > -INF ) {
				l = -INF, r = inter[j].first;
				found = true; break;
			}
			if ( las != -INF && las <= inter[j].first ) {
				l = las, r = inter[j].first;
				found = true; break;
			}
			chkmax ( las, inter[j].second );
		}
		if ( !found && las < INF ) l = las, r = INF;
		wint ( l == -INF || r == INF ? -1 : ( l <= r ? r - l + 1 : 0 ) );
		putchar ( '\n' );
	}
	return 0;
}

Details

  关于负环的做得太少,拿着就不知所措 qwq,而且考场上前面浪费太多时间根本没来得及向这题……

posted @   Rainybunny  阅读(120)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示