2024.11.19 CW 模拟赛

题目 & 题解

T1

算法

贪心.

思路

分类讨论.

  • 对于 4 次比赛均参加了的账号, 其一定是真人.
  • 对于参加了 3 次比赛的账号, 如果他有小号, 那么小号最多是只参加了该账号没有参加的那一场比赛的一个账号.
  • 对于参加了 2 次比赛的账号, 假设他只参加了 1, 3 这两场比赛, 那么他最好与恰好参加了 2, 4 这两场比赛的人同属一个人.
    其次, 如果没有恰好参加了 2, 4 两场比赛的账号, 那么可以与单独参加第 2 或 4 场比赛的账号属于一个人.
    到了最后, 就只剩仅参加一场比赛的账号了, 容易发现, 此时真人最少有 4 场比赛中仅参加一场比赛的账号数量的最大值.
#include "iostream"
#include "bitset"

using namespace std;

template <typename T>
inline void read(T &x)
{
    x = 0;
    char ch = getchar();
    while (!isdigit(ch))
        ch = getchar();
    while (isdigit(ch))
        x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
    return;
}

const int N = 1e5 + 1;

int n, ans = 0;
int s[4], sum[16];
bitset<N> f[4];

inline void init()
{
    read(n);
    for (int i = 0; i < 4; ++i)
    {
        int m;
        read(m);
        for (int j = 1; j <= m; ++j)
        {
            int x;
            read(x);
            f[i][x] = 1;
        }
    }
    return;
}

inline void calculate()
{
    for (int i = 1; i <= n; ++i)
    {
        if (f[0][i] + f[1][i] + f[2][i] + f[3][i] == 1)
        {
            for (int j = 0; j < 4; ++j)
                if (f[j][i])
                    s[j]++;
        }
        else if (f[0][i] + f[1][i] + f[2][i] + f[3][i] == 2)
        {
            int hsh = 0;
            for (int j = 0; j < 4; ++j)
                if (f[j][i])
                    hsh = (hsh << 2) + j;
            sum[hsh]++;
        }
        else if (f[0][i] + f[1][i] + f[2][i] + f[3][i] == 3)
        {
            for (int j = 0; j < 4; ++j)
                if (!f[j][i])
                    s[j]--;
            ans++;
        }
        else if (f[0][i] + f[1][i] + f[2][i] + f[3][i] == 4)
            ans++;
    }

    if (sum[11] > sum[1])
    {
        ans = ans + sum[11];
        s[0] = s[0] - sum[11] + sum[1];
        s[1] = s[1] - sum[11] + sum[1];
    }
    else
    {
        ans = ans + sum[1];
        s[2] = s[2] - sum[1] + sum[11];
        s[3] = s[3] - sum[1] + sum[11];
    }

    if (sum[7] > sum[2])
    {
        ans = ans + sum[7];
        s[0] = s[0] - sum[7] + sum[2];
        s[2] = s[2] - sum[7] + sum[2];
    }
    else
    {
        ans = ans + sum[2];
        s[1] = s[1] - sum[2] + sum[7];
        s[3] = s[3] - sum[2] + sum[7];
    }

    if (sum[6] > sum[3])
    {
        ans = ans + sum[6];
        s[0] = s[0] - sum[6] + sum[3];
        s[3] = s[3] - sum[6] + sum[3];
    }
    else
    {
        ans = ans + sum[3];
        s[1] = s[1] - sum[3] + sum[6];
        s[2] = s[2] - sum[3] + sum[6];
    }

    ans = ans + max(max(s[0], s[1]), max(0, max(s[2], s[3])));
    ans += !ans;

    printf("%d\n", n - ans);
    return;
}

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

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

T2

算法

字典树, 字符串.

思路

考虑将所给的字符串建成一颗字典树(包括目标字符串).

那么输入一个字符相当于从该节点走到一个子节点,

按一次 tab 呢?
如果该节点是一个字符串的结尾, 就跳到下一个字符串结尾的位置.
如果该节点不是一个完整的字符串, 就走到子树内字典序最小的字符串的结尾.

最后预处理出所有的边, 再跑一次 bfs 求最短路即可.

#include "iostream"
#include "string"
#include "queue"

using namespace std;

const int N = 2e6 + 1, M = 2e6 + 1;

int n, ed[N];
string aim, s[N];
basic_string<int> g[N], pst;

namespace Trie
{
    struct Node
    {
        int son[26];
        int fa;
        bool isend = 0;
    } t[M];
    int cnt = 0;

    inline void insert(int num)
    {

        int nw = 0, len = s[num].size();
        if (num == 1)
            pst += nw;
        for (int i = 0; i < len; ++i)
        {
            int ch = s[num][i] - 'a';
            if (!t[nw].son[ch])
                t[nw].son[ch] = ++cnt, t[cnt].fa = nw, pst += cnt, g[nw] += cnt;
            nw = t[nw].son[ch];
            if (i == len - 1)
                t[nw].isend = 1, ed[num] = nw;
        }
        if (num ^ (n + 1))
            for (int x : pst)
                g[x] += ed[num];
        return;
    }
}

inline void build()
{
    for (int i = 1; i <= n + 1; ++i)
        pst.clear(), Trie::insert(i);
    for (int i = 2; i <= n; ++i)
        g[ed[i - 1]] += ed[i],
            g[ed[n]] += ed[1];
    return;
}

inline void init()
{
    cin >> n >> aim;
    for (int i = 1; i <= n; ++i)
        cin >> i[s];
    s[n + 1] = aim;
    build();
    return;
}

int dis[M];
bool vis[M];
queue<int> q;

inline void calculate(int s)
{

    for (int i = 1; i <= 1e6; ++i)
        dis[i] = 1e9, vis[i] = 0;
    dis[s] = 0;
    q.push(s);

    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        if (u == ed[n + 1])
        {
            cout << dis[u] << '\n';
            return;
        }
        if (vis[u])
            continue;
        vis[u] = 1;
        for (int v : g[u])
        {
            if (dis[v] > dis[u] + 1)
            {
                dis[v] = dis[u] + 1;
                if (!vis[v])
                    q.push(v);
            }
        }
    }

    return;
}

inline void solve()
{
    init();
    calculate(0);
    return;
}

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