zoukankan      html  css  js  c++  java
  • Solution -「UR #2」「UOJ #32」跳蚤公路

    (mathcal{Description})

      Link.

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

      (nle100)(mle10^4)

    (mathcal{Solution})

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

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

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

    [min_j{f(n-1,u,j)+jx}lemin_k{f(n,u,k)+kx} ]

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

    [xgefrac{f(n-1,u,j)-f(n,u,k)}{k-j} ]

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

    (mathcal{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; // xin(-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 ( '
    ' );
    	}
    	return 0;
    }
    

    (mathcal{Details})

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

  • 相关阅读:
    使用scp进行远程数据传输时避免输入密码(scp without password)
    scons用户指南翻译(附gcc/g++参数详解)
    StringIO 模块用于在内存缓冲区中读写数据
    注意变换的顺序
    为什么static成员必须在类外初始化
    Visual Studio中删除所有空行
    rendering order of skybox
    解决VS中注释乱码的问题
    一道数论题目
    First Chance Exception
  • 原文地址:https://www.cnblogs.com/rainybunny/p/13567723.html
Copyright © 2011-2022 走看看