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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现