2024.12.19 CW 模拟赛

题面 & 题解

T1

算法

树形 dp.

思路

由于给定的仇视关系为一棵树, 所以我们可以考虑在这颗树上进行 dp.

考虑设 \(f_{u, i}\) 表示当前枚举到第 \(u\) 个人, ta的烟花从 \(l_i + i\) 开始定制的最小仇视值.

那么就有以下转移方程:

\[f_{u, i} = \min(f_{v, j}\ +\ [l_u + i,\ l_u + i + t_i - 1] \cap [l_v + j,\ l_v + j + t_j - 1]) \]

其中 \(v\)\(u\) 的儿子节点.

#include "iostream"
#include "vector"

using namespace std;

constexpr int N = 1e3 + 10;

#define int long long

int n, m;
int l[N], r[N], t[N];
vector<pair<int, int>> e[N];

void init() {
    cin >> n >> m;
    for (int i = 1; i <= n; ++i)
        cin >> l[i] >> r[i] >> t[i], r[i] = r[i] - t[i] + 1;
    for (int i = 1; i <= m; ++i) {
        int u, v, w;
        cin >> u >> v >> w;
        e[u].emplace_back(v, w);
        e[v].emplace_back(u, w);
    }
}

int f[N][N];
bool vis[N][N];

int deal(int a, int b, int c, int d, int val) { return max(0ll, min(b, d) - max(a, c) + 1) * val; }

int dfs(int u, int fa, int st) {
    if (vis[u][st])
        return f[u][st];
    vis[u][st] = 1;
    for (auto [v, w] : e[u]) {
        if (v == fa)
            continue;
        int mn = 5e18;
        for (int i = 0; i <= r[v] - l[v]; ++i)
            mn = min(mn, dfs(v, u, i) + deal(l[u] + st, l[u] + st + t[u] - 1, l[v] + i, l[v] + i + t[v] - 1, w));
        f[u][st] += mn;
    }
    return f[u][st];
}

void calculate() {
    for (int i = 1; i <= n; ++i) {
        int mn = 5e18;
        for (int j = 0; j <= r[i] - l[i]; ++j)
            mn = min(mn, dfs(i, 0, j));
        return cout << mn << '\n', void();
    }
}

void solve() {
    init();
    calculate();
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);
    solve();
    return 0;
}

T2

算法

质因数分解.

思路

考虑每一个插入 \(\mathbb{S}\) 的数, 如果该数含有质因子 \(p \notin \mathbb{T}\) 并且次幂不为 3 的倍数, 那么取任意的 \(x\) 都不可能满足条件(因为 \(x\) 的因子只能在 \(\mathbb{T}\) 中取).

接下来将使得 \(S_i \times k = \lambda^3\)\(k\) 全部处理出来, 开一个 \(set\) 记录下来, 查询时直接输出即可.

#pragma GCC optimize("Ofast")

#include "iostream"
#include "cmath"
#include "algorithm"
#include "set"
#include "ext/pb_ds/hash_policy.hpp"
#include "ext/pb_ds/assoc_container.hpp"

using namespace std;
using namespace __gnu_pbds;

constexpr int N = 5e2 + 10;

#define int long long

template <class T>
void read(T &x)
{
    x = 0;
    char ch = getchar();
    while (ch < '0' or ch > '9')
        ch = getchar();
    while (ch >= '0' and ch <= '9')
        x = x * 10 + ch - 48, ch = getchar();
}

void print(int x)
{
    if (x > 9)
        print(x / 10);
    putchar(x % 10 + '0');
}

constexpr int INF = 9223372036854775807;

int n, Q, p[N];

void init()
{
    read(n);
    for (int i = 1; i <= n; ++i)
        read(p[i]);
    sort(p + 1, p + n + 1);
    read(Q);
}

int qpow(int x, int y)
{
    __int128 ret = 1;
    for (; y; y >>= 1, x *= x)
    {
        if (ret > INF)
            return 0;
        if (y & 1)
            ret *= x;
    }
    if (ret > INF or ret <= 0)
        return 0;
    return ret;
}

int deal(int x)
{
    __int128 ret = 1;
    for (int i = 1; p[i] <= x and i <= n; ++i)
        if (!(x % p[i]))
        {
            int tmp = 0;
            while (!(x % p[i]))
                ++tmp, x /= p[i];
            if (tmp % 3)
                ret *= qpow(p[i], 3 - tmp % 3);
            if (ret > INF or ret <= 0)
                return 0;
        }
    return ret;
}

bool check(int x)
{
    for (int i = 1; p[i] <= x and i <= n; ++i)
        while (!(x % p[i]))
            x /= p[i];
    int t = round(cbrt(x));
    if (t * t * t == x)
        return 1;
    return 0;
}

gp_hash_table<int, int> t;
struct Node
{
    int num, v;
    friend bool operator<(Node x, Node y)
    {
        if (x.v ^ y.v)
            return x.v > y.v;
        return x.num < y.num;
    }
};
set<Node> ans;

void calculate()
{
    while (Q--)
    {
        int op, x;
        read(op);
        if (op == 1)
        {
            read(x);
            if (check(x))
            {
                int tmp = deal(x);
                if (tmp)
                {
                    if (t[tmp])
                        ans.erase({tmp, t[tmp]});
                    ++t[tmp];
                    ans.insert({tmp, t[tmp]});
                }
            }
        }
        else if (op == 2)
        {
            read(x);
            int tmp = deal(x);
            if (tmp)
            {
                ans.erase({tmp, t[tmp]});
                --t[tmp];
                if (tmp)
                    ans.insert({tmp, t[tmp]});
            }
        }
        else
            print(ans.begin()->num), putchar('\n');
    }
}

void solve()
{
    init();
    calculate();
}

signed main()
{
    solve();
    return 0;
}

T3

原题链接

算法

博弈论, dp, 线段树.

思路

#include "iostream"

using namespace std;

template <class T>
inline void read(T &x) {
    x = 0;
    char ch = getchar();
    while (ch < '0' or ch > '9')
        ch = getchar();
    while (ch >= '0' and ch <= '9')
        x = x * 10 + ch - 48, ch = getchar();
}

void print(__int128 x) {
    if (x < 0)
        x = -x, putchar('-');
    if (x > 9)
        print(x / 10);
    putchar(x % 10 + '0');
}

#define int long long

constexpr int N = 5e6 + 10;
constexpr __int128 INF = 1e20;

int n, fst;
__int128 f[N];
int a[N], v1, v2;
int to[N], nxt[N], head[N], idx = 0;

void adde(int u, int v) { to[++idx] = v, nxt[idx] = head[u], head[u] = idx; }

void init() {
    idx = 0;
    read(n), read(fst);
    for (int i = 1; i <= n; ++i)
        read(a[i]), head[i] = -1, f[i] = INF;
    for (int v = 2; v <= n; ++v) {
        int u;
        read(u);
        adde(u, v);
    }
    read(v1), read(v2);
}

class Segment_Tree {
protected:
    int P;
    __int128 tr[N << 2];

public:
    void build() {
        P = 1;
        while (P <= n + 1)
            P <<= 1;
        for (int i = 1; i <= (n << 2); ++i)
            tr[i] = INF;
    }

    void update(int x, __int128 k) {
         tr[x += P] = k;
        for (x >>= 1; x; x >>= 1)
            tr[x] = min(tr[x << 1], tr[x << 1 | 1]);
    }

    __int128 query() { return tr[1]; }

} st;

bool flag[N], win[N];

void dfs(int u) {
    int cnt = 0;
    for (int i = head[u]; ~i; i = nxt[i]) {
        int v = to[i];
        dfs(v);
        cnt += !win[v];
    }
    if (!cnt)
        win[u] = flag[u] = 0;
    else
        win[u] = 1, flag[u] = (cnt == 1);
}

void deal(int u) {
    if (!win[u])
        st.update(u, INF);
    for (int i = head[u]; ~i; i = nxt[i]) {
        int v = to[i];
        deal(v);
        if (!win[u])
            f[u] = min(f[u], f[v]);
        else if (flag[u] and !win[v])
            f[u] = f[v];
    }
    if (!win[u]) {
        f[u] = min(f[u], (__int128)v1 * a[u] + (__int128)v2 * st.query());
        st.update(u, a[u]);
    }
}

void calculate() {
    st.build();
    dfs(1);
    if ((fst and !win[1]) or (!fst and win[1]))
        return puts("0"), void();
    for (int i = 1; i <= n; ++i)
        if (!win[i])
            st.update(i, a[i]);
    deal(1);
    if (f[1] == INF)
        f[1] = -1;
    print(f[1]), putchar('\n');
}

void solve() {
    init();
    calculate();
}

signed main() {
    int T;
    read(T);
    while (T--)
        solve();
    return 0;
}
posted @   Steven1013  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示