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
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
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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步