2024牛客寒假算法基础集训营1
2024牛客寒假算法基础集训营1
A
解题思路:
按照
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;
using piii = pair<ll, pair<ll, ll>>;
void solve()
{
int n;
cin >> n;
string s;
cin >> s;
vector<bool> vis(40);
for (auto c : s)
{
if (c == 'D')
{
vis['D' - 'A'] = true;
}
else if (c == 'F' && vis['D' - 'A'] == true)
{
vis[c - 'A'] = true;
}
else if (c == 'S' && vis['F' - 'A'] == true)
{
vis[c - 'A'] = true;
}
}
if (vis['D' - 'A'] && vis['F' - 'A'] && vis['S' - 'A'])
{
cout << 1 << ' ';
}
else
{
cout << 0 << ' ';
}
for (int i = 0; i < 30; i++)
{
vis[i] = false;
}
for (auto c : s)
{
if (c == 'd')
{
vis['d' - 'a'] = true;
}
else if (c == 'f' && vis['d' - 'a'] == true)
{
vis[c - 'a'] = true;
}
else if (c == 's' && vis['f' - 'a'] == true)
{
vis[c - 'a'] = true;
}
}
if (vis['d' - 'a'] && vis['f' - 'a'] && vis['s' - 'a'])
{
cout << 1 << ' ';
}
else
{
cout << 0 << ' ';
}
cout << endl;
}
int main()
{
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
B
解题思路:
如果
其余封锁起码四把火,左右各两把。
暴力记录枚举情况添火判断即可。
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;
using piii = pair<ll, pair<ll, ll>>;
void solve()
{
int n;
cin >> n;
set<pii> s;
bool l = false;
bool tr = false;
ll res = 3;
ll minx = 1e18;
ll maxx = -1e18;
for (int i = 1; i <= n; i++)
{
ll r, c;
cin >> r >> c;
minx = min(minx, c);
maxx = max(maxx, c);
if (r == 1)
{
if (s.find({r + 1, c}) != s.end())
{
if (c < 0)
{
l = true;
}
else if (c > 0)
{
tr = true;
}
}
if (s.find({r + 1, c - 1}) != s.end())
{
if (c - 1 >= 0)
{
tr = true;
}
else
{
l = true;
}
}
if (s.find({r + 1, c + 1}) != s.end())
{
if (c + 1 > 0)
{
tr = true;
}
else
{
l = true;
}
}
}
else
{
if (s.find({r - 1, c}) != s.end())
{
if (c < 0)
{
l = true;
}
else if (c > 0)
{
tr = true;
}
}
if (s.find({r - 1, c - 1}) != s.end())
{
if (c - 1 >= 0)
{
tr = true;
}
else
{
l = true;
}
}
if (s.find({r - 1, c + 1}) != s.end())
{
if (c + 1 > 0)
{
tr = true;
}
else
{
l = true;
}
}
}
s.insert({r, c});
}
if (s.find({2, 0}) != s.end())
{
res--;
}
if (s.find({1, -1}) != s.end())
{
res--;
}
if (s.find({1, 1}) != s.end())
{
res--;
}
ll ans = 0;
if (!l)
{
if (s.size())
{
auto x = minx;
if (x <= 0)
{
ans += 1;
}
else
{
ans += 2;
}
}
else
{
ans += 2;
}
}
// cout << ans << endl;
if (!tr)
{
if (s.size())
{
auto x = maxx;
if (x >= 0)
{
ans += 1;
}
else
{
ans += 2;
}
}
else
{
ans += 2;
}
}
ans = min(ans, res);
cout << ans << endl;
}
int main()
{
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
C
解题思路:
先求出总不满意度
尝试插入发现,越往后插队,
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;
using piii = pair<ll, pair<ll, ll>>;
void solve()
{
ll n, q, t;
cin >> n >> q >> t;
vector<ll> a(n + 1), pre(n + 10);
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
sort(a.begin() + 1, a.end());
ll sum = 0;
for (int i = 1; i <= n; i++)
{
sum += (n - i + 1) * a[i];
pre[i] = a[i] + pre[i - 1];
}
while (q--)
{
ll m;
cin >> m;
auto check = [&](int mid)
{
ll cur = t * (n - mid + 1);
return cur <= m;
};
int l = 0;
int r = n + 1;
while (l + 1 < r)
{
int mid = l + r >> 1;
if (check(mid))
{
r = mid;
}
else
{
l = mid;
}
}
cout << pre[r - 1] + t << endl;
}
}
int main()
{
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
return 0;
}
D
解题思路:
累乘发现,
实际上,我们将这少数不同的数分别变成从
所以,我们可以
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;
using piii = pair<ll, pair<ll, ll>>;
const int N = 1e5 + 10;
const int inf = 1e9;
int n, q;
ll a[N];
set<ll> s, ans;
bool check(ll x)
{
ll res = 1;
for (int i = 1; i <= n; i++)
{
res *= a[i] + x;
if (abs(res) > inf)
{
return false;
}
}
ans.insert(res);
return true;
}
void solve()
{
cin >> n >> q;
ans.insert(0);
for (int i = 1; i <= n; i++)
{
scanf("%lld", &a[i]);
s.insert(a[i]);
}
if (s.size() < 20)
{
// 将i从1/-1开始递增和递减,最多根号n次
for (auto i : s)
{
ll cur = -i + 1;
while (check(cur))
{
cur++;
}
cur = -i - 1;
while (check(cur))
{
cur--;
}
}
}
while (q--)
{
int x;
scanf("%d", &x);
if (ans.count(x))
{
puts("Yes");
}
else
{
puts("No");
}
}
}
int main()
{
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
return 0;
}
E
解题思路:
数据范围很小,对于每场比赛对决枚举所有胜负可能。
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;
using piii = pair<ll, pair<ll, ll>>;
void solve()
{
int n, m;
cin >> n >> m;
vector<int> a(n + 1);
vector<pii> q;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
for (int i = 1; i <= m; i++)
{
int u, v;
cin >> u >> v;
if (u == 1 || v == 1)
{
a[1] += 3;
continue;
}
q.push_back({u, v});
}
m = q.size();
ll ans = 1e18;
ll sum = pow(3, m);
for (int i = 0; i < sum; i++)
{
ll t = i;
vector<int> p;
vector<int> b = a;
for (int i = 1; i <= m; i++)
{
p.push_back(t % 3);
t /= 3;
}
int cur = 0;
for (auto x : p)
{
int u = q[cur].fi;
int v = q[cur].se;
cur++;
if (x == 0)
{
b[u]++;
b[v]++;
}
else if (x == 1)
{
b[u] += 3;
}
else
{
b[v] += 3;
}
}
ll cnt = 0;
for (int i = 1; i <= n; i++)
{
if (b[i] > b[1])
{
cnt++;
}
}
ans = min(ans, cnt + 1);
}
cout << ans << endl;
}
int main()
{
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
F
解题思路:
本题考察第二类斯特林数的通项公式。
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;
using piii = pair<ll, pair<ll, ll>>;
const int N = 1e5;
const int mod = 1e9 + 7;
ll f[N + 1];
ll invf[N + 1];
ll qmi(ll a, ll b)
{
ll res = 1;
while (b)
{
if (b & 1)
{
res = res * a % mod;
}
a = a * a % mod;
b >>= 1;
}
return res;
}
ll C(ll a, ll b)
{
if (b == 0 || a == b)
{
return 1;
}
return (f[a] * invf[b] % mod) * invf[a - b] % mod;
}
void solve()
{
int n, m;
cin >> n >> m;
if (n < m)
{
cout << 0 << endl;
return;
}
f[0] = 1;
for (int i = 1; i <= N; i++)
{
f[i] = f[i - 1] * i % mod;
}
invf[N] = qmi(f[N], mod - 2) % mod;
for (int i = N - 1; i; i--)
{
invf[i] = invf[i + 1] * (i + 1) % mod;
}
ll ans = 0;
for (int i = 0; i <= m; i++)
{
ll sign = (i & 1) ? -1 : 1;
ans = (ans + (sign * C(m, i) * qmi(m - i, n) % mod)) % mod;
ans = (ans + mod) % mod;
}
ans = ans * invf[m] % mod;
cout << ans << endl;
}
int main()
{
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
return 0;
}
G
解题思路:
显然,满减券的时候小的都叠加起来,手机里的钱加满减能得到上限。记得将手机里没用完的钱加上。
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;
using piii = pair<ll, pair<ll, ll>>;
void solve()
{
ll n, m;
cin >> n >> m;
vector<pii> v(n + 1);
for (int i = 1; i <= n; i++)
{
cin >> v[i].fi >> v[i].se;
}
sort(v.begin() + 1, v.end());
ll pre = 0;
ll ans = m;
for (int i = 1; i <= n; i++)
{
pre += v[i].se;
if (v[i].fi - pre <= m)
{
ans = max(ans, v[i].fi + m - (v[i].fi - pre));
}
}
cout << ans << endl;
}
int main()
{
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
H
解题思路:
我们总重量枚举二进制中所有的
举例:
将其划分为几段
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;
using piii = pair<ll, pair<ll, ll>>;
void solve()
{
int n, m;
cin >> n >> m;
vector<int> v(n + 1), w(n + 1);
for (int i = 1; i <= n; i++)
{
cin >> v[i] >> w[i];
}
ll ans = 0;
ll cur = 0;
ll res = 0;
for (int i = 30; i >= 0; i--)
{
if (m >> i & 1)
{
res = 0;
ll t = cur + (1 << i) - 1;
for (int j = 1; j <= n; j++)
{
if ((w[j] | t) == t)
{
res += v[j];
}
}
ans = max(ans, res);
cur += 1 << i;
}
}
res = 0;
for (int i = 1; i <= n; i++)
{
if ((w[i] | cur) == cur)
{
res += v[i];
}
}
ans = max(ans, res);
cout << ans << endl;
}
int main()
{
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
I
解题思路:
按照题目所给构造方法进行构造,然后统计二者某一数值的平均或者其他统计特征,找到明显区别,即可判断。
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;
using piii = pair<ll, pair<ll, ll>>;
void solve()
{
ll n;
cin >> n;
n = 1e5;
double s = 0;
for (int i = 1; i <= n; i++)
{
ll a, b, c;
cin >> a >> b >> c;
s += c;
}
s /= n;
if (s >= 20)
{
puts("buaa-noob");
}
else
{
puts("bit-noob");
}
}
int main()
{
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
return 0;
}
J
解题思路:
二分。
每次二分判断尝试构造任务过程,使得二者过程期间最大距离小于
在构造过程当中,假设我们当前遍历到了
如果存在
对于
因为,如果
我们按照时间倒推,如果
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;
using piii = pair<ll, pair<ll, ll>>;
void solve()
{
int n, x, y;
cin >> n >> x >> y;
vector<int> a(n + 1);
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
}
ll l = -1;
ll r = 1e9 + 1;
auto check = [&](ll mid)
{
set<int> s;
if (abs(x - y) > mid)
{
return false;
}
s.insert(x);
s.insert(y);
for (int i = 1; i <= n; i++)
{
while (s.size() && abs((*s.begin()) - a[i]) > mid)
{
s.erase(s.begin());
}
while (s.size() && abs((*s.rbegin()) - a[i]) > mid)
{
s.erase(*s.rbegin());
}
if (s.empty())
{
return false;
}
s.insert(a[i]);
}
return true;
};
while (l + 1 < r)
{
ll mid = l + r >> 1;
if (check(mid))
{
r = mid;
}
else
{
l = mid;
}
}
cout << r << endl;
}
int main()
{
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
return 0;
}
K
解题思路:
找到每个环。对该环搜索。每个结点开始有
将所有环的正确答案集合数量累乘,即答案。
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;
using piii = pair<ll, pair<ll, ll>>;
const int mod = 998244353;
void solve()
{
int n;
cin >> n;
vector<int> a(n + 1);
vector<string> s(n + 1);
vector<int> indeg(n + 1);
vector<bool> vis(n + 1);
for (int i = 1; i <= n; i++)
{
cin >> a[i] >> s[i];
indeg[a[i]]++;
}
queue<int> q;
for (int i = 1; i <= n; i++)
{
if (!indeg[i])
{
q.push(i);
}
}
while (q.size())
{
auto t = q.front();
q.pop();
indeg[a[t]]--;
vis[t] = true;
if (!indeg[a[t]])
{
q.push(a[t]);
}
}
ll ans = 1;
for (int i = 1; i <= n; i++)
{
if (vis[i])
{
continue;
}
int u = i;
int v = u;
while (true)
{
vis[v] = true;
v = a[v];
if (v == u)
{
break;
}
}
int cnt = 0;
for (int j = 0; j < 5; j++)
{
v = u;
int idx = j;
while (true)
{
idx = s[v][idx] - 'A';
v = a[v];
if (v == u)
{
break;
}
}
if (s[u][idx] == s[u][j])
{
cnt++;
}
}
ans = ans * cnt % mod;
}
cout << ans << endl;
}
int main()
{
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
return 0;
}
L
解题思路:
简单画个图,答案为
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;
using piii = pair<ll, pair<ll, ll>>;
void solve()
{
ll c,d,h,w;
cin >> c >> d >> h >> w;
cout << 3 * w * c << endl;
}
int main()
{
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
M
解题思路:
分别从左和右开始排放。
如果总长度是
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;
using piii = pair<ll, pair<ll, ll>>;
void solve()
{
int n;
cin >> n;
if (n % 6 == 0)
{
cout << n / 6 << endl;
}
else
{
cout << (n / 6) * 2 << endl;
}
}
int main()
{
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期
· 全程使用 AI 从 0 到 1 写了个小工具
· 从文本到图像:SSE 如何助力 AI 内容实时呈现?(Typescript篇)