2022“杭电杯”中国大学生算法设计超级联赛(5)

2022“杭电杯”中国大学生算法设计超级联赛(5)

[题目链接](Search Result (hdu.edu.cn))

L Buy Figurines

题目大意

有n个人买东西,第i个人会在ai时刻来排队,花费si的时间。现有m个队伍,每个人会选择当前时刻中,排队人数最少的队伍,如果有多个最少的,选择编号最小的队伍。问最后一个人离开的时间。

题解

线段树,叶子节点表示队伍。

查找某个人排哪个队伍:如果左边的结点的最小值小于等于右边的,就去左边,否则就去右边。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;
int t, n, m;
ll last[maxn];
struct Node
{
    int a, s;
    bool operator<(const Node &b) const
    {
        return a < b.a;
    }
} peo[maxn];
struct Node2
{
    ll end;
    int id;
    bool operator<(const Node2 &b) const
    {
        return end > b.end;
    }
};
struct Tree
{
    int l, r, num;
} tree[maxn << 2];
void PushUp(int rt)
{
    tree[rt].num = min(tree[rt << 1].num, tree[rt << 1 | 1].num);
}
void Build(int l, int r, int rt)
{
    tree[rt].l = l;
    tree[rt].r = r;
    tree[rt].num = 0;
    if (l == r)
        return;
    int m = (l + r) >> 1;
    Build(l, m, rt << 1);
    Build(m + 1, r, rt << 1 | 1);
    PushUp(rt);
}
void Update(int rt, int id, int x)
{
    if (tree[rt].l == tree[rt].r)
    {
        tree[rt].num += x;
        return;
    }
    int m = (tree[rt].l + tree[rt].r) >> 1;
    if (id <= m)
        Update(rt << 1, id, x);
    else
        Update(rt << 1 | 1, id, x);
    PushUp(rt);
}
int Query(int rt)
{
    if (tree[rt].l == tree[rt].r)
        return tree[rt].l;
    if (tree[rt << 1].num <= tree[rt << 1 | 1].num)
        return Query(rt << 1);
    else
        return Query(rt << 1 | 1);
}
int Get(int rt, int id)
{
    if (tree[rt].l == tree[rt].r)
        return tree[rt].num;
    int m = (tree[rt].l + tree[rt].r) >> 1;
    if (id <= m)
        return Get(rt << 1, id);
    else
        return Get(rt << 1 | 1, id);
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> t;
    while (t--)
    {
        cin >> n >> m;
        for (int i = 1; i <= n; i++)
            cin >> peo[i].a >> peo[i].s;
        for (int i = 1; i <= m; i++)
            last[i] = 0;
        sort(peo + 1, peo + 1 + n);
        Build(1, m, 1);
        priority_queue<Node2> q;
        for (int i = 1; i <= n; i++)
        {
            while (q.size() && q.top().end <= peo[i].a)
            {
                int id = q.top().id;
                Update(1, id, -1);
                q.pop();
            }
            int id = Query(1);
            if (Get(1, id) == 0)
                last[id] = peo[i].a + peo[i].s;
            else
                last[id] += peo[i].s;
            q.push({last[id], id});
            Update(1, id, 1);
        }
        cout << *max_element(last + 1, last + 1 + m) << endl;
    }
    return 0;
}

J Bragging Dice

题目大意

两个人玩游戏,每个人有n个骰子,每个人只能摇一次。然后有两个选择,可以说一个现在2n个骰子的情况,如有4个1点;或挑战对方,若对方说对了,则对方赢,否则,挑战方赢。

特殊规则:

1、若此前未有人说过1点,则1点可以被当成任意点数。

2、若n个骰子都是一样的点数,则有n+1个该点数。

3、若n个骰子点数各不相同,则每个点数的个数都为0。

题解

当双方都摇出全部不同的点数时,此时先手无论如何说都是会被挑战成功的。除此之外的情况,先手都能说出最大的x个y,此时后手没有正确的情况可以说,一定会被先手挑战成功。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;
int t, n, x;
int a[7], b[7];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> t;
    while (t--)
    {
        cin >> n;
        memset(a, 0, sizeof a);
        memset(b, 0, sizeof b);
        for (int i = 1; i <= n; i++)
        {
            cin >> x;
            a[x]++;
        }
        for (int i = 1; i <= n; i++)
        {
            cin >> x;
            b[x]++;
        }
        bool ok1 = 1, ok2 = 1;
        for (int i = 1; i <= 6; i++)
            if (a[i] > 1)
                ok1 = 0;
        for (int i = 1; i <= 6; i++)
            if (b[i] > 1)
                ok2 = 0;
        if (ok1 && ok2)
            cout << "Just a game of chance." << endl;
        else
            cout << "Win!" << endl;
    }
    return 0;
}

C Slipper

题目大意

给定一棵以1为根的树,每条边都有边权w,经过一条边的花费为边的边权。同时对于两个节点u,v,如果两点深度之差为k,那么只需要花费p就可以从u到v,或者从v到u。求从点s到点t的最小花费。

题解

最短路dijkstra。

本题难点在于深度之差为k的点之间的连边。在第i层和第i+k层之间增加两个点:其中一个点为所有第i层的点到该点,该点到所有的i+k层;另一个点为所有第i+k层的点到该点,该点到所有的i层。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> P;
const int maxn = 3e6 + 5;
const int maxm = 8e6 + 5;
int T, n, k, p, s, t;
ll dis[maxn];
int head[maxn], cnt, maxdeep;
vector<int> v[maxn];
struct Edge
{
    int to, w, next;
} edge[maxm];
void init()
{
    memset(head, -1, sizeof head);
    maxdeep = cnt = 0;
    for (int i = 0; i < maxn; i++)
        v[i].clear();
    return;
}
void add(int u, int v, int w)
{
    edge[cnt].w = w;
    edge[cnt].to = v;
    edge[cnt].next = head[u];
    head[u] = cnt++;
}
void dij()
{
    memset(dis, 0x3f3f3f3f, sizeof dis);
    priority_queue<P, vector<P>, greater<P>> q;
    dis[s] = 0;
    q.push(P(0, s));
    while (!q.empty())
    {
        P p = q.top();
        q.pop();
        int u = p.second;
        if (u == t)
            return;
        if (dis[u] < p.first)
            continue;
        for (int i = head[u]; ~i; i = edge[i].next)
        {
            int v = edge[i].to, w = edge[i].w;
            if (dis[v] > dis[u] + w)
            {
                dis[v] = dis[u] + w;
                q.push(P(dis[v], v));
            }
        }
    }
}
void dfs(int u, int fa, int deep)
{
    v[deep].push_back(u);
    maxdeep = max(maxdeep, deep);
    for (int i = head[u]; ~i; i = edge[i].next)
    {
        int v = edge[i].to;
        if (v != fa)
            dfs(v, u, deep + 1);
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> T;
    while (T--)
    {
        init();
        cin >> n;
        for (int i = 1; i < n; i++)
        {
            int u, v, w;
            cin >> u >> v >> w;
            add(u, v, w);
            add(v, u, w);
        }
        cin >> k >> p >> s >> t;
        dfs(1, 0, 0);
        for (int i = 0; i <= maxdeep; i++)
        {
            if (i + k > maxdeep)
                break;
            n++;
            for (auto e : v[i])
                add(n, e, p);
            for (auto e : v[i + k])
                add(e, n, 0);
            n++;
            for (auto e : v[i])
                add(e, n, p);
            for (auto e : v[i + k])
                add(n, e, 0);
        }
        dij();
        cout << dis[t] << endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值