Gym - 102279L - Left or Right? How about neither?

题意:

给定一个长为 n 的数组 a,现在起点在 x,终点在 y,前进(向右)花费 R 的能量,后退花费 L 的能量,并且当在 i 位置时,可以花费 C 的能量瞬移到 j ( a j = a i a_j = a_i )。问到达终点需要花费的最少能量。(n <= 1e5, L, R, C, a i a_i <= 1e9)

链接:

https://vjudge.net/problem/Gym-102279L

解题思路:

考虑最短路,对于相邻点,直接连有向边,重点在于瞬移如何建边。显然,不能直接两两连边,考虑到花费均为 C,对于同种权值,引一个辅助点 t,t 向该种权值点连权 C 2 \frac{C}{2} 的双向边,这样就达到两两连接的效果。

参考代码:

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define pb push_back
#define sz(a) ((int)a.size())
#define mem(a, b) memset(a, b, sizeof a)
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 4e5 + 5;
const int maxm = 1e6 + 5;
const int mod = 1e9 + 7;
//const int inf = 0x3f3f3f3f;

typedef pair<ll, int> pli;
const ll inf = 0x3f3f3f3f3f3f3f3f;
vector<pli> G[maxn];
pli a[maxn];
ll dis[maxn];
int n, s, t;
priority_queue<pli, vector<pli>, greater<pli> > q;
 
void add(int u, int v, ll w){
 
    G[u].pb({w, v});
}
 
ll dij(){
 
    for(int i = 1; i <= n; ++i) dis[i] = inf;
    dis[s] = 0, q.push({dis[s], s});
    while(!q.empty()){
 
        int u = q.top().second; ll d = q.top().first; q.pop();
        if(d != dis[u]) continue;
        for(int i = 0; i < sz(G[u]); ++i){
 
            int v = G[u][i].second; ll w = G[u][i].first;
            if(dis[v] > dis[u] + w){
 
                dis[v] = dis[u] + w;
                q.push({dis[v], v});
            }
        }
    }
    return dis[t];
}
 
int main() {
 
    ios::sync_with_stdio(0); cin.tie(0);
    ll l, r, c; cin >> n >> l >> r >> c >> s >> t;
    for(int i = 1; i <= n; ++i){
 
        cin >> a[i].first; a[i].second = i;
    }
    sort(a + 1, a + 1 + n);
    for(int i = 2; i <= n; ++i) add(i, i - 1, l * 2);
    for(int i = 1; i < n; ++i) add(i, i + 1, r * 2);
    int lim = n;
    for(int i = 1, j; i <= lim; i = j){
 
        ++n; add(a[i].second, n, c), add(n, a[i].second, c);
        for(j = i + 1; j <= lim && a[j].first == a[j - 1].first; ++j) add(a[j].second, n, c), add(n, a[j].second, c);
    }
    ll ret = dij() / 2;
    cout << ret << endl;
    return 0;
}
发布了55 篇原创文章 · 获赞 0 · 访问量 1258

猜你喜欢

转载自blog.csdn.net/weixin_44059127/article/details/102528377