首页 > 其他分享 >伊吹萃香 题解

伊吹萃香 题解

时间:2024-10-07 19:49:51浏览次数:8  
标签:int 题解 白洞 路口 黑洞 伊吹萃 hole dis

题意

(很复杂,真的不想概括,以下是原题面)

在幻想乡,伊吹萃香是能够控制物体密度的鬼王。因为能够控制密度,所以萃香能够制造白洞和黑洞,并可以随时改变它们。某一天萃香闲着无聊,在妖怪之山上设置了一些白洞或黑洞,由于引力的影响,给妖怪们带来了很大的麻烦。于是他们决定找出一条消耗体力最少的路,来方便进出。已知妖怪之山上有 \(N\) 个路口(编号 \(1\)..\(N\) ),每个路口都被萃香设置了一定质量白洞或者黑洞。原本在各个路口之间有M条单向路,走过每一条路需要消耗一定量的体力以及 \(1\) 个单位的时间。由于白洞和黑洞的存在,走过每条路需要消耗的体力也就产生了变化,假设一条道路两端路口黑白洞的质量差为 \(delta\):

  1. 从有白洞的路口走向有黑洞的路口,消耗的体力值减少 \(delta\),若该条路径消耗的体力值变为负数的话,取为 \(0\)。

  2. 从有黑洞的路口走向有白洞的路口,消耗的体力值增加 \(delta\)。

  3. 如果路口两端均为白洞或黑洞,消耗的体力值无变化。

由于光是放置黑洞白洞不足以体现萃香的强大,所以她决定每过 \(1\) 个单位时间,就把所有路口的白洞改成黑洞,黑洞改成白洞。当然在走的过程中你可以选择在一个路口上停留 \(1\) 个单位的时间,如果当前路口为白洞,则不消耗体力,否则消耗 \(s_i\) 的体力。现在请你计算从路口 \(1\) 走到路口 \(N\) 最小的体力消耗。保证一定存在道路从路口 \(1\) 到路口 \(N\)。

题解

最短路,维护一个 \(f(i, h)\) 表示到达 \(i\) 点且到达之后的洞为 \(h\)。

先考虑停留的情况:

若该洞为白洞:

\[f(u, 1 - h) = f(u, h) \]

为黑洞:

\[f(u, 1 - h) = f(u, h) + s_u \]

(判黑白洞就用时间加最开始的形态模 \(2\),\(1 - h\) 就是把原来的洞反过来)

如果不停留:

\[f(v, h ^ {\prime}) = \min\{f(v, h ^ {\prime}), f(u, h) + w\} \]

(\(w\) 为当前消耗代价,\(h ^ {\prime}\) 为到达 \(v\) 之后的洞型)

\(w\) 可以开个函数算一下。

顺便提一嘴,如果用堆跑最短路会被卡(也有可能是我常数太大了),建议改成队列(反正也能过)。

namespace zqh {
const int N = 5005;

struct node { // 结点状态
    int hol;
    int wei;
    int sta;
} h[N];
struct point { // 最短路的状态
    int u, t, k;
};
int n, m, dis[N][2]; // 上文 f 数组
vector<pii> g[N]; // 存图

int calc(int weiu, int weiv, int holu, int holv, int w) { // 计算代价,w 为最开始的代价
    if (holu == holv) {
        return w;
    }
    if (holu == 1 && holv == 0) {
        return w + abs(weiu - weiv);
    }
    if (holu == 0 && holv == 1) {
        return max(w - abs(weiu - weiv), 0LL);
    }
}

void dijkstra() { // 貌似不是 dij
    memset(dis, 0x3f, sizeof dis); // 赋初值
    queue<point> q;
    q.push({1, 0, 0});
    dis[1][h[1].hol] = 0;
    while (q.size()) {
        point t = q.front();
        //			cout << t.u << " " << t.t << " " << t.k << endl;
        q.pop();
        int u = t.u, hole_u = ((h[u].hol + t.t) & 1); // hole_u 为当前的洞状态
        if (hole_u == 0) { // 停留,判黑白洞,赛时没盘,成功挂分
            if (dis[u][1 - hole_u] > dis[u][hole_u]) {
                dis[u][1 - hole_u] = dis[u][hole_u];
                q.push({u, t.t + 1, dis[u][1 - hole_u]});
            }
        } else {
            if (dis[u][1 - hole_u] > dis[u][hole_u] + h[u].sta) {
                dis[u][1 - hole_u] = dis[u][hole_u] + h[u].sta;
                q.push({u, t.t + 1, dis[u][1 - hole_u]});
            }
        }
        for (int i = 0; i < g[u].size(); i++) {
            int v = g[u][i].first, w = g[u][i].second;
            int hole_v = ((h[v].hol + t.t + 1) & 1); // hole_v 同理
            int val = calc(h[u].wei, h[v].wei, hole_u, 1 - hole_v, w); // 计算代价
            if (dis[v][hole_v] > dis[u][hole_u] + val) { // 转移
                dis[v][hole_v] = dis[u][hole_u] + val;
                q.push({v, t.t + 1, dis[v][hole_v]});
            }
        }
    }
}

void init() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        cin >> h[i].hol;
    }
    for (int i = 1; i <= n; i++) {
        cin >> h[i].wei;
    }
    for (int i = 1; i <= n; i++) {
        cin >> h[i].sta;
    }
    for (int i = 1; i <= m; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        g[u].push_back({v, w});
    }
}

void solve() {
    dijkstra();
    cout << min(dis[n][0], dis[n][1]); // 最后可以是黑白两种
}

void main() {
    init();
    solve();
}
}  // namespace zqh
/*
4 5
1 0 1 0
10 10 100 10
5 20 15 10
1 2 30
2 3 40
1 3 20
1 4 200
3 4 200

130
*/

\[\]

标签:int,题解,白洞,路口,黑洞,伊吹萃,hole,dis
From: https://www.cnblogs.com/zphh/p/18450520

相关文章

  • CF1117E Decypher the String题解
    传送门神奇的题。这是一道交互题。给定一个字符串\(s\),我们拥有若干操作,但是你不知道,第\(i\)个操作形如\(a_i,b_i\)表示交换字符串\(s\)中的第\(a_i\)位和\(a_j\)位。比如操作序列依次为\((1,2),(2,3)\),给定字符串为xyz。那么我们执行第一次操作后......
  • 题解 QOJ2559【Endless Road】/ SS241006D【套路题】
    PetrozavodskWinter2022.Day2.KAISTContest+KOITST2021XXIIOpenCupnamedafterE.V.Pankratiev,GrandPrixofDaejeon题目描述现在有\(10^9\)个花盆,依次编号为\(1,2,\dots,10^{9}\)。给定\(n\)个二元组\(L_i,R_i(L_i<R_i)\),我们将进行\(n\)次以下操......
  • CF722F Cyclic Cipher 题解
    传送门给定\(n\)个数列,第\(i\)个数列包含\(k_i\)个不超过\(m\)的互不相同的正整数(从\(1\)开始标号)。每一秒将每个数列中的数左移一个位置(即将每个数的下标\(-1\),下标\(1\)的数下标变为\(k_i\)),并记录由每个数列的第一个数组成的序列。\(10^{100}\)秒过......
  • [NOIP2023] 双序列拓展 题解
    qaq首先我们考虑其实这个条件就是要满足\(f\)严格比\(g\)大或\(f\)严格比\(g\)小。在这里只讨论大于。然后考虑到对于一个\(i\)如果不满足,我们可以把对应数组向右移一位看是否满足,如果还是不满足就无解了。考虑对于现在满足的\(i\),我们可以分别把两个指针向右移一......
  • EGOI2024 简单题解
    Day1T1InfiniteRace由于只有重复超过一个人才肯定是跑过一圈的,所以只用用一个数组做标记就可以了,每超过一次就打上标记,否则去掉标记。T2Bouquet定义\(dp[i]\)为,以第\(i\)种郁金香结尾的选法中最大可选的郁金香数量,易得状态转移方程为:\(dp[i]=max{dep[j]}+1(j<l_i\le......
  • mysql登录遇到ERROR 1045问题解决方法
    遇到MySQL登录时出现 ERROR1045(访问被拒绝,用户名或密码错误),可以通过以下步骤来解决:1.确认用户名和密码检查用户名和密码:确认在连接数据库时输入的用户名和密码是否正确。尝试在命令行中连接数据库,确认是否能成功登录:bash mysql-uyour_username-p2.重......
  • 题解:AT_abc374_c [ABC374C] Separated Lunch
    无耻的广告更好的阅读体验~最近在搞个人博客博客园的差点忘了更了。已经沦落到在写这种水题题解了。题目翻译有\(n\)队人,每个队人数不同,把他们分成2组(同一队的不能拆开),使两组人数差距尽量小。形式化题意:有\(n\)个数,把它们分成两组,使两组和的差尽量小。说句闲话:感觉这......
  • P3527 MET-Meteors 题解
    Solution单次二分:二分时间,做这个时间前的所有操作,然后线性统计。注意到可以整体二分,直接整体二分是\(O(n\log^2n)\)。考虑扫描序列,用线段树维护每个时间段内该位置的增加值,差分一下可以实现。将这棵线段树持久化一下,一个国家所有位置同时二分即可\(O(n\logn)\),可惜空间太......
  • P3250 网络 题解
    Solution单次二分:问“重要度\(\gex\)的所有操作,且\(t\)时间点还存在的所有操作中,是否有不经过这个点的”整体二分:保持操作、询问按时间有序,即预先按时间排序,下传时保持有序;对于一次Solve,对于所有重要度\(\gemid+1\)的操作(加入、删除),考虑与询问按时间混合排序,然后依次......
  • P3215 括号修复 题解
    Statement维护一个括号序列,有以下操作:区间覆盖区间翻转区间反转(左括号变右括号,右括号变左括号)区间问最少改多少位能使括号序列合法,保证有解Solution单纯没想到答案怎么算。。。首先一段括号序,如果消除中间的所有匹配,最终一定形如))))(((,这个信息是可合并的设这时左括......