2024CCPC区域赛哈尔滨站

  • define时间:
#define itn int
#define int long long
#define ind long double
#define yes cout << "Yes"
#define no cout << "No"
#define pii pair<long long, long long>
#define pci pair<char, int>
#define re return;

M.Weird Ceiling

签到。简化题意:

\(f(a,b)\):如果 \(d\) 是小于等于 \(b\)\(a\) 的最小约数,\(f(a,b)=a/d\)

void solve()
{
    cin >> n;
    ans = 0;
    vector<int> v;
    for (int i = 1; i <= sqrt(n); i++)
    {
        if (n % i == 0)
        {
            v.emplace_back(i);
            if (i != n / i)
                v.emplace_back(n / i);
        }
    }
    sort(v.begin(), v.end());
    for (int i = 0; i < v.size() - 1; i++)
    {
        ans += (v[i + 1] - v[i]) * (n / v[i]);
    }
    ans += 1;
    cout << ans;
}

C. Giving Directions in Harbin

模拟。

一开始想用 map 赋值比大小来表示转向,但是忘记这是环形,所以 wa 了。

map<char, int> mp;
void solve()
{
    mp['N'] = 0, mp['E'] = 1, mp['S'] = 2, mp['W'] = 3;
    cin >> n;
    num = 0;
    for (int i = 1; i <= n; i++)
    {
        cin >> g[i] >> a[i];
    }
    cout << n * 2 - 1 << ' ' << g[1] << '\n';
    g[n + 1] = g[n];
    vector<char> v;
    for (int i = 1; i <= n; i++)
    {
        cout << "Z " << a[i] << '\n';
        if (g[i] == 'N' && g[i + 1] == 'W' ||
            g[i] == 'W' && g[i + 1] == 'S' ||
            g[i] == 'S' && g[i + 1] == 'E' ||
            g[i] == 'E' && g[i + 1] == 'N')
        {
            cout << "L\n";
        }
        else if(mp[g[i]]==mp[g[i+1]])
        {
           1;
        }
        else{
            cout << "R\n";
        }
    }
}

G. Welcome to Join the Online Meeting!

bfs。写的有点史。

入队顺序无所谓,所以先找一个非调试者入队。

然后如果他邀请的人不是调试者,那么这个人可以入队并邀请其他人。

(思路是这样,但实际都会入队,只是调试者会直接出队。)

vector<int> e[N];
int vis[N]; // 判断是否是调试程序的人
int vs[N];  // 判断是否被已经被邀请了
void solve()
{
    cin >> n >> m >> k;
    for (int i = 1; i <= k; i++)
    {
        cin >> a[i];
        vis[a[i]] = 1;
    }
    while (m--)
    {
        cin >> x >> y;
        e[x].emplace_back(y);
        e[y].emplace_back(x);
    }
    queue<int> q;
    for (int i = 1; i <= n; i++)
    {
        if (!vis[i])
        {
            vs[i] = 1;
            q.push(i);
            break;
        }
    }
    num = 0;
    /* vector<int> v(1, 0); */
    vector<vector<int>> ans;
    while (q.size())
    {
        auto u = q.front();
        q.pop();
        if (vis[u])
        {
            continue;
        }
        vis[u] = 1;
        vector<int> tp;
        tp.emplace_back(u);
        for (auto i : e[u])
        {
            if (!vs[i])
            {
                tp.emplace_back(i);
                q.push(i);
                vs[i] = 1;
            }
        }
        if (tp.size() > 1)
            ans.push_back(tp);
    }
    for (int i = 1; i <= n; i++)
    {
        if (!vs[i])
        {
            no;
            re;
        }
    }
    yes;
    cout << '\n';
    cout << ans.size() << '\n';
    for (auto i : ans)
    {
        cout << i[0] << ' ' << i.size() - 1 << ' ';
        for (auto j = 1; j < i.size(); j++)
        {
            cout << i[j] << ' ';
        }
        cout << '\n';
    }
}

K. Farm Management

贪心。

如代码注释,答案显然会在两种情况中产生:

  • 考虑扩充价值最大方案为无限时间,剩余时间都给它
  • 考虑对于第 i 种方案时间为 0,其余时间按价值从大到小分配

所以我们排序一下,然后前缀和存一下时间和价值,再二分一下就好了。

struct stu
{
    int x, l, r;
} f[N];
void solve()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
    {
        cin >> f[i].x >> f[i].l >> f[i].r;
    }
    sort(f + 1, f + 1 + n, [](stu a, stu b)
         { return a.x > b.x; });
    int suml = 0;
    sum = 0;
    for (int i = 1; i <= n; i++)
    {
        sum += f[i].x * f[i].l;
        suml += f[i].l;
    }
    // 第一种情况是考虑扩充最大方案为无限时间,剩余时间都给他
    ans = sum + (m - suml) * f[1].x;
    // 第二种情况是考虑对于第i种方案时间为0,其余时间价值按大到小分配
    for (int i = 1; i <= n; i++)
    {
        a[i] = a[i - 1] + f[i].r - f[i].l;
        b[i] = b[i - 1] + f[i].x * (f[i].r - f[i].l);
    }
    for (int i = 1; i <= n; i++)
    {
        t = m - (suml - f[i].l); //除去i方案后总共多的时间
        auto it = upper_bound(a + 1, a + 1 + n, t) - a - 1;
        auto tp = sum - f[i].x * f[i].l + b[it] + f[it + 1].x * (t - a[it]);
        ans = max(ans, tp);
    }
    cout << ans;
}

J. New Energy Vehicle

贪心。

为了距离最大化容易想到:在抵达某个充电站前尽量使用该电瓶的电。

因为充电站按顺序排放,我们可以用小顶堆来维护,一开始只放入每种电瓶最前面的一个充电站。

再用一个 next 容器来记录,这种充电站的下一个充电站位置。

每次抵达一个充电站,我们就让该种充电站的下一个充电站入堆。

void solve()
{
    cin >> n >> m;
    priority_queue<pii, vector<pii>, greater<>> q;
    vector<int> nx(m + 1), mp(n + 1, m + 1);//加一个哨兵点,实际不存在
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        a1[i] = a[i];//存储电瓶容量
    }
    for (int i = 1; i <= m; i++)
    {
        cin >> b[i] >> c[i];
    }
    for (int i = m; i > 0; i--)
    {
        nx[i] = mp[c[i]]; // 记录给i充电的下个一充电站位置
        mp[c[i]] = i;
    }
    for (int i = 1; i <= n; i++)
    {
        q.push({mp[i], i});
    }
    int ans = 0;
    int cnt = 1;
    while (q.size())
    {
        auto [x, t] = q.top();
        q.pop();
        int tp = b[cnt] - ans;
        if (cnt <= m && a[t] >= tp)//如果这段距离小于该种电瓶电量
        {
            a[t] -= tp;
            ans += tp;
            a[c[cnt]] = a1[c[cnt]];
            q.push({nx[cnt], c[cnt]});
            if (a[t] && t != c[cnt])
                q.push({x, t});
            cnt++;
        }
        else
        {
            ans += a[t];
            a[t] = 0;
        }
    }
    cout << ans;
}
posted @ 2025-08-20 23:28  lengling  阅读(69)  评论(0)    收藏  举报