• 「题解」Codeforces 360E Levko and Game


    现在明确我们的目的:能赢就选择赢的方案,否则尝试平局;并不是求和对方差值更大的方案。

    考虑一个赢/平局的方案,考虑每一条边,没有被任何一个经过,那么调整到任何值都是无所谓的;如果仅被 (s_1) 经过,调整到 (l) 是更优的;如果仅被 (s_2) 经过,调整到 (r) 是更优的;如果同时被 (s_1,s_2) 经过,那么一定是一个平局的方案,把这条边改得更小还会使 (s_1,s_2) 经过这里,如果把这条边改得更大反而可能让 (s_1,s_2) 走其他路从而变成一个 (s_1) 赢的方案,如果不存在让 (s_1) 赢的方案再把它改成 (l) ,也就是尽可能地让 (s_1,s_2) 一起走到这里,促成平局。

    综上所述,一定存在一个最优方案使得每条边的权值要不然为 (l),要不然为 (r)

    考虑如何让 (s_1) 赢:对于一条边 ((u,v))

    • (dis(s_1,u)geq dis(s_2,u)),那么 (s_1) 一定不会走这条路,因为走到这条路之后和 (s_2) 的最优路线重合,一定不会赢,所以改成 (r)(s_2) 走这条路的开销更大;

    • (dis(s_1,u)<dis(s_1,u)),同理,(s_2) 走这条路会使 (s_1) 赢,那么 (s_2) 不会走这条路,改成 (l)(s_1) 走这条路的开销更小。

    现在判断完了 (s_1) 能不能赢,如果不能赢就尽可能平局,和上面的思路基本一致:

    • (dis(s_1,u)>dis(s_2,u)),那么 (s_1) 一定不会走这条路,因为走到这条路之后和 (s_2) 的最优路线重合,一定不会平局,所以改成 (r)(s_2) 走这条路的开销更大;

    • (dis(s_1,u)leq dis(s_1,u)),同理,(s_2) 走这条路会平局或 (s_1) 赢 ,那么 (s_2) 不会走这条路,改成 (l)(s_1) 走这条路的开销更小。

    先钦点所有的边都是 (r),每次跑 Dijkstra 然后看哪些边要改权值就改,没有边权值要改时再判断,易做到 (mathcal{O}(kmlog n))

    实际上可以在最短路每次松弛的时候判断当前边的权值是多少,时间复杂度 (mathcal{O}(mlog n))

    (mathcal{Code})

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #define int long long 
    typedef long long ll;
    template <typename T> T Max(T x, T y) { return x > y ? x : y; }
    template <typename T> T Min(T x, T y) { return x < y ? x : y; }
    template <typename T>
    T& read(T& r) {
    	r = 0; bool w = 0; char ch = getchar();
    	while(ch < '0' || ch > '9') w = ch == '-' ? 1 : 0, ch = getchar();
    	while(ch >= '0' && ch <= '9') r = r * 10 + (ch ^ 48), ch = getchar();
    	return r = w ? -r : r;
    }
    const int N = 200010;
    const ll INF = 0x7fffffffffffffff;
    int n, m, k;
    int s1, s2, t;
    ll dis[N];
    struct Edge {
    	int to, val1, val2, id;
    	bool fl;
    	Edge(int x = 0, int y = 0, int z = 0, int p = 0) { to = x; val1 = y; val2 = z; id = p; }
    };
    int ans[N];
    std::vector<Edge>vec[N];
    std::queue<int>q;
    void Dij(int s1, int s2, int fl) {
    	for(int i = 1; i <= n; ++i) dis[i] = INF;
    	dis[s1] = 1; dis[s2] = 0;
    	q.push(s1); q.push(s2);
    	while(!q.empty()) {
    		int x = q.front(); q.pop();
    		for(Edge &e : vec[x]) {
    			int v = e.to, w = (e.fl = ((dis[x]&1) == fl)) ? e.val1 : e.val2;
    			if(dis[v] > dis[x] + w) {
    				dis[v] = dis[x] + w;
    				q.push(v);
    			}
    		}
    	}
    }
    signed main() {
    	read(n); read(m); read(k);
    	read(s1); read(s2); read(t);
    	for(int i = 1; i <= m; ++i) {
    		int u, v, l; read(u); read(v); read(l);
    		vec[u].push_back(Edge(v, l<<1, l<<1, 0));
    	}
    	for(int i = 1; i <= k; ++i) {
    		int u, v, l, r; read(u); read(v); read(l); read(r);
    		vec[u].push_back(Edge(v, l<<1, r<<1, i));
    	}
    	Dij(s1, s2, 1);
    	if(dis[t] & 1) {
    		puts("WIN");
    		for(int i = 1; i <= n; ++i)
    			for(Edge e : vec[i])
    				ans[e.id] = e.fl ? e.val1 : e.val2;
    		for(int i = 1; i <= k; ++i) printf("%lld ", ans[i]/2);
    	}
    	else {
    		Dij(s2, s1, 0);
    		if(!(dis[t]&1)) {
    			puts("DRAW");
    			for(int i = 1; i <= n; ++i)
    				for(Edge e : vec[i])
    					ans[e.id] = e.fl ? e.val1 : e.val2;
    			for(int i = 1; i <= k; ++i) printf("%lld ", ans[i]/2);
    		}
    		else {
    			puts("LOSE");
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    HDU 1017—A Mathematical Curiosity
    N !
    L
    J
    Danganronpa
    A water problem
    hdu 5461 Largest Point
    India and China Origins hdu 5652 (BFS+二分)
    D (多校训练三) poj1919 (二分)
    Discovering Gold lightoj 1030 (dp+期望)
  • 原文地址:https://www.cnblogs.com/do-while-true/p/15146277.html
Copyright © 2020-2023  润新知