2024牛客寒假算法基础集训营1
A
#include <bits/stdc++.h>
#define endl '\n'
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef double db;
const ll mod = 998244353;
const int N = 1e6 + 10, M = 25;
void solve()
{
int n;
cin >> n;
string s;
cin >> s;
int cnt = 0;
for (auto i : s)
{
if (i == 'D' && cnt == 0)
cnt++;
if (i == 'F' && cnt == 1)
cnt++;
if (i == 'S' && cnt == 2)
cnt++;
}
cout << (cnt == 3 ? 1 : 0) << " ";
cnt = 0;
for (auto i : s)
{
if (i == 'd' && cnt == 0)
cnt++;
if (i == 'f' && cnt == 1)
cnt++;
if (i == 's' && cnt == 2)
cnt++;
}
cout << (cnt == 3 ? 1 : 0) << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int _ = 1;
cin >> _;
while (_--)
solve();
return 0;
}
B
注意特判一下用\((1,-1),(1,1),(2,0)\)围起来的特殊情况
#include <bits/stdc++.h>
#define endl '\n'
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef double db;
const ll mod = 998244353;
const int N = 1e6 + 10, M = 25;
int dx[] = {-1, -1, -1, 1, 1, 1}, dy[] = {-1, 0, 1, -1, 0, 1};
map<pii, bool> mp;
void solve()
{
ll n;
cin >> n;
mp.clear();
vector<pii> p(n);
for (auto &[x, y] : p)
{
cin >> x >> y;
mp[{x, y}] = 1;
}
sort(p.begin(), p.end(), [&](pll a, pll b)
{
if(a.y!=b.y)
return a.y < b.y;
return a.x<b.x; });
int ans = 3, ansr = 2, ansl = 2;
for (auto [x, y] : p)
{
if (y < 0)
{
for (int j = 0; j < 6; j++)
{
int xx = x + dx[j], yy = y + dy[j];
if (xx <= 2 && xx >= 1 && yy <= 1e9 && yy >= -1e9)
{
if (mp[{xx, yy}])
ansl = 0;
}
}
ansl = min(ansl, 1);
}
else if (y > 0)
{
for (int j = 0; j < 6; j++)
{
int xx = x + dx[j], yy = y + dy[j];
if (xx <= 2 && xx >= 1 && yy <= 1e9 && yy >= -1e9)
{
if (mp[{xx, yy}])
ansr = 0;
}
}
ansr = min(ansr, 1);
}
else
{
ansl = min(ansl, 1);
ansr = min(ansr, 1);
}
}
if (mp[{2, 0}])
ans--;
if (mp[{1, -1}])
ans--;
if (mp[{1, 1}])
ans--;
cout << min(ans, ansl + ansr) << endl;
// cout << ansl + ansr << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int _ = 1;
cin >> _;
while (_--)
solve();
return 0;
}
C
二分答案
#include <bits/stdc++.h>
#define endl '\n'
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef double db;
const ll mod = 998244353;
const int N = 1e6 + 10, M = 25;
int dx[] = {-1, -1, -1, 1, 1, 1}, dy[] = {-1, 0, 1, -1, 0, 1};
map<pii, bool> mp;
void solve()
{
ll n, q, tc;
cin >> n >> q >> tc;
vector<ll> t(n + 1);
for (int i = 1; i <= n; i++)
cin >> t[i];
sort(t.begin() + 1, t.end());
for (int i = 1; i <= n; i++)
t[i] += t[i - 1];
ll ans = t[n] + tc;
for (int i = 1; i <= q; i++)
{
ll m;
cin >> m;
auto chk = [&](int x)
{
ll r = tc * (n - x);
return r <= m;
};
int l = 0, r = n;
while (l < r)
{
int mid = l + r >> 1;
if (chk(mid))
r = mid;
else
l = mid + 1;
}
cout << t[l] + tc << endl;
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int _ = 1;
// cin >> _;
while (_--)
solve();
return 0;
}
D
考虑答案不多,暴力预处理出所有答案
数组的第一个和第二个元素中,至少存在一个\(\le \sqrt{10^9}\)
按照这个枚举即可
#include <bits/stdc++.h>
#define endl '\n'
#define x first
#define y second
#define ls(x) (a[x].l)
#define rs(x) (a[x].r)
#define sum(x) a[x].sum
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef double db;
const ll mod = 1e9 + 7;
const int N = 7e7 + 10, M = 25;
random_device rd;
mt19937_64 gen(rd());
void solve()
{
map<ll, bool> mp;
int n, q;
cin >> n >> q;
vector<ll> a(n + 1);
for (int i = 1; i <= n; i++)
cin >> a[i], mp[a[i]] = 1;
set<ll> s;
ll B = sqrt(2e9);
auto chk = [&](ll x)
{
if (mp[-x])
{
s.insert(0);
return;
}
ll res = 1;
for (int i = 1; i <= n; i++)
{
res *= (a[i] + x);
if (abs(res) > 1e9)
return;
}
s.insert(res);
};
for (int i = -B; i <= B; i++)
for (int j = 1; j <= 2; j++)
chk(i - a[j]), chk(-i - a[j]);
while (q--)
{
ll x;
cin >> x;
cout << (s.find(x) != s.end() ? "Yes" : "No") << endl;
}
}
int main()
{
// cout << setprecision(5);
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int _ = 1;
// cin >> _;
while (_--)
solve();
return 0;
}
E
爆搜答案
#include <bits/stdc++.h>
#define endl '\n'
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef double db;
const ll mod = 998244353;
const int N = 1e6 + 10, M = 25;
void solve()
{
int n, m;
cin >> n >> m;
vector<ll> a(n + 1, 0);
for (int i = 1; i <= n; i++)
cin >> a[i];
vector<pii> race(m);
for (auto &[u, v] : race)
cin >> u >> v;
int ans = n;
vector<int> path(m + 1, 0);
auto dfs = [&](const auto &dfs, int u) -> void
{
if (u == m)
{
vector<ll> b = a;
for (int i = 0; i < m; i++)
{
auto [u, v] = race[i];
if (path[i] == 1)
b[u] += 3;
else if (path[i] == 2)
b[v] += 3;
else
b[u]++, b[v]++;
}
int res = 0;
for (int i = 2; i <= n; i++)
if (b[i] > b[1])
res++;
ans = min(ans, res + 1);
return;
}
for (int i = 1; i <= 3; i++)
{
path[u] = i;
dfs(dfs, u + 1);
}
};
dfs(dfs, 0);
cout << ans << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int _ = 1;
cin >> _;
while (_--)
solve();
return 0;
}
F
把题意抽象出来就是第二类斯特林数板子
```cpp
void solve()
{
vector<ll> fac(N), invfac(N);
auto qmi = [&](ll a, ll b) -> ll
{
ll res = 1;
while (b)
{
if (b & 1)
res = res * a % mod;
b >>= 1;
a = a * a % mod;
}
return res;
};
auto init = [&](int n)
{
fac[0] = 1;
for (int i = 1; i <= n; i++)
fac[i] = fac[i - 1] * i % mod;
invfac[n] = qmi(fac[n], mod - 2);
for (int i = n - 1; i >= 0; i--)
invfac[i] = invfac[i + 1] * (i + 1) % mod;
};
auto C = [&](int n, int m)
{
return fac[n] * invfac[m] % mod * invfac[n - m] % mod;
};
int n, m;
cin >> n >> m;
init(1e5);
ll ans = 0;
for (int i = 0; i <= m; i++)
{
ll res = (i & 1) ? -1 : 1;
res = res * C(m, i) % mod;
res = res * qmi(m - i, n) % mod;
ans = (ans + res + mod) % mod;
}
ans = ans * invfac[m] % mod;
cout << ans << endl;
}
G
将优惠卷按优惠幅度排序,枚举能用哪些,能用大的就一定能用小的
#include <bits/stdc++.h>
#define endl '\n'
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef double db;
const ll mod = 998244353;
const int N = 1e6 + 10, M = 25;
void solve()
{
ll n, m;
cin >> n >> m;
vector<pll> a(n);
for (auto &[x, y] : a)
cin >> x >> y;
sort(a.begin(), a.end());
ll ans = m, sum = 0;
for (auto [x, y] : a)
{
sum += y;
if (m + sum >= x)
ans = max(ans, m + sum);
}
cout << ans << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int _ = 1;
cin >> _;
while (_--)
solve();
return 0;
}
H
贪心,考虑将某一位1变成0,后面就可以全是1了
比如:\((110110)_2\)可以变成\((101111)_2\)
#include <bits/stdc++.h>
#define endl '\n'
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef double db;
const ll mod = 998244353;
const int N = 1e6 + 10, M = 25;
random_device rd; // 将用于为随机数引擎获得种子
mt19937_64 gen(time(0)); // 以播种标准 mersenne_twister_engine
void solve()
{
ll n, m, ans = 0;
bool st = 0;
cin >> n >> m;
vector<pll> a(n);
for (auto &[x, y] : a)
cin >> x >> y;
auto cal = [&](ll t) -> ll
{
ll res = 0;
for (auto [x, y] : a)
if ((t | y) == t)
res += x;
return res;
};
ans = cal(m);
for (int i = 40; i >= 0; i--)
if ((m >> i) & 1)
{
ll res = m;
res ^= (1ll << i);
for (int j = i - 1; j >= 0; j--)
res |= (1ll << j);
ans = max(ans, cal(res));
}
cout << ans << endl;
}
int main()
{
cout << setprecision(5);
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int _ = 1;
cin >> _;
while (_--)
solve();
return 0;
}
I
模拟可以发现方案二的点会集中靠近圆心,而方案一是均匀的。
根据这条性质可以找到一个差异较大的边界,直接判断距离即可
#include <bits/stdc++.h>
#define endl '\n'
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef double db;
const ll mod = 998244353;
const int N = 1e6 + 10, M = 25;
void solve()
{
int n, cnt = 0;
cin >> n;
vector<pll> p(n);
for (auto &[x, y] : p)
cin >> x >> y;
vector<ll> dist(n);
for (auto [x, y] : p)
{
if (abs(x) <= 70 && abs(y) <= 70)
cnt++;
}
cout << (cnt >= 75000 ? "buaa-noob" : "bit-noob") << endl;
}
int main()
{
cout << setprecision(5);
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int _ = 1;
// cin >> _;
while (_--)
solve();
return 0;
}
J
一log做法:
二分答案
因为每个位置一定有人去,所有最后两人的位置一定是\(a[j],a[n]\),这样可以贪心的倒着找到最小的\(j\),满足\(abs(a[j]-a[n])\le mid\),然后就递归的变成的一个子问题了。
#include <bits/stdc++.h>
#define endl '\n'
#define x first
#define y second
#define ls(x) (a[x].l)
#define rs(x) (a[x].r)
#define sum(x) a[x].sum
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef double db;
const ll mod = 1e9 + 7;
const int N = 7e7 + 10, M = 25;
random_device rd;
mt19937_64 gen(rd());
void solve()
{
int n, x, y;
cin >> n;
n += 2;
vector<int> a(n + 1);
for (int i = 1; i <= n; i++)
cin >> a[i];
auto chk = [&](int t) -> bool
{
int idx = n;
while (idx > 1)
{
int pos = idx;
int mx = a[pos], mi = a[pos];
for (int i = idx - 1; i >= 1; i--)
{
if (abs(mx - a[i]) <= t && abs(mi - a[i]) <= t)
idx = i;
mx = max(mx, a[i]), mi = min(mi, a[i]);
}
if (idx == pos)
return false;
}
return true;
};
int l = abs(a[1] - a[2]), r = 1e9;
while (l < r)
{
int mid = l + r >> 1;
if (chk(mid))
r = mid;
else
l = mid + 1;
}
cout << l << endl;
}
int main()
{
// cout << setprecision(5);
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int _ = 1;
// cin >> _;
while (_--)
solve();
return 0;
}
二log做法:
用set处理出每个点的所有可能性,只要每个点都不为空,就一定存在一种满足的方案
#include <bits/stdc++.h>
#define endl '\n'
#define x first
#define y second
#define ls(x) (a[x].l)
#define rs(x) (a[x].r)
#define sum(x) a[x].sum
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef double db;
const ll mod = 1e9 + 7;
const int N = 7e7 + 10, M = 25;
random_device rd;
mt19937_64 gen(rd());
void solve()
{
int n, x, y;
cin >> n >> x >> y;
vector<int> a(n);
for (int i = 0; i < n; i++)
cin >> a[i];
auto chk = [&](int t) -> bool
{
int lst = y;
set<int> s;
if (abs(x - y) <= t)
s.insert(x);
for (auto pos : a)
{
if (s.size() && abs(pos - lst) <= t)
s.insert(lst);
while (s.size() && abs(*s.begin() - pos) > t)
s.erase(s.begin());
while (s.size() && abs(*s.rbegin() - pos) > t)
s.erase(*s.rbegin());
lst = pos;
if (s.empty())
return false;
}
return true;
};
int l = abs(x - y), r = 1e9;
while (l < r)
{
int mid = l + r >> 1;
if (chk(mid))
r = mid;
else
l = mid + 1;
}
cout << l << endl;
}
int main()
{
// cout << setprecision(5);
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int _ = 1;
// cin >> _;
while (_--)
solve();
return 0;
}
K
把题目按照\(i\)到\(a[i]\)连边,会形成若干内向基环树和链,并且答案取决于环,随机选环上一点,枚举并检查答案的正确性(排列复合仍为排列,所以只要一点确定,其他点也就确定了),最后将答案乘起来
#include <bits/stdc++.h>
#define endl '\n'
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef double db;
const ll mod = 998244353;
const int N = 2e5 + 100, M = 25;
void solve()
{
ll n, ans = 1;
cin >> n;
vector<string> s(n + 1);
vector<int> a(n + 1), d(n + 1, 0), vis(n + 1, 0);
vector<vector<int>> rec(n + 1, vector<int>(6, 0));
for (int i = 1; i <= n; i++)
{
cin >> a[i] >> s[i];
d[a[i]]++;
}
queue<int> q;
for (int i = 1; i <= n; i++)
if (!d[i])
q.push(i);
while (q.size())
{
auto t = q.front();
q.pop();
vis[t] = 1;
if (--d[a[t]] == 0)
q.push(a[t]);
}
for (int i = 1; i <= n; i++)
if (!vis[i])
{
ll res = 0;
for (int j = i; !vis[j]; j = a[j])
vis[j] = 1;
for (int j = 0; j < 5; j++)
{
ll u = i, v = j;
while (!rec[u][v])
{
rec[u][v] = 1;
v = s[u][v] - 'A', u = a[u];
if (u == i)
break;
}
if (u == i && v == j)
res++;
}
ans = ans * res % mod;
}
cout << ans << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int _ = 1;
// cin >> _;
while (_--)
solve();
return 0;
}
L
结论赛时猜的
当光源高度低于2h时,俯视图中墙一定在三角形的中位线上
高于2h是,阴影到达不了边界,一定变小
#include <bits/stdc++.h>
#define endl '\n'
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef double db;
const ll mod = 998244353;
const int N = 1e6 + 10, M = 25;
void solve()
{
db c, d, h, w;
cin >> c >> d >> h >> w;
cout << 3 * w * c << endl;
}
int main()
{
cout << setprecision(10);
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int _ = 1;
cin >> _;
while (_--)
solve();
return 0;
}
M
手动模拟一下,答案显然
#include <bits/stdc++.h>
#define endl '\n'
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef double db;
const ll mod = 998244353;
const int N = 1e6 + 10, M = 25;
void solve()
{
ll n;
cin >> n;
cout << (n / 6) * (n % 6 != 0 ? 2 : 1) << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int _ = 1;
cin >> _;
while (_--)
solve();
return 0;
}