2024.11.19 CW 模拟赛

题目 & 题解

T1

算法

贪心.

思路

分类讨论.

  • 对于 4 次比赛均参加了的账号, 其一定是真人.
  • 对于参加了 3 次比赛的账号, 如果他有小号, 那么小号最多是只参加了该账号没有参加的那一场比赛的一个账号.
  • 对于参加了 2 次比赛的账号, 假设他只参加了 1, 3 这两场比赛, 那么他最好与恰好参加了 2, 4 这两场比赛的人同属一个人.
    其次, 如果没有恰好参加了 2, 4 两场比赛的账号, 那么可以与单独参加第 2 或 4 场比赛的账号属于一个人.
    到了最后, 就只剩仅参加一场比赛的账号了, 容易发现, 此时真人最少有 4 场比赛中仅参加一场比赛的账号数量的最大值.
复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
#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 求最短路即可.

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
#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  阅读(6)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
展开