qwq
A. 日历游戏
将每个日期当作一种状态,当前状态可以转移的状态只有+1天 或者 +1个月;
SG处理每种状态 最后判断即可。
也有一种规律做法,点此查看题解即可;
#include <bits/stdc++.h>
using u32 = unsigned;
using i64 = long long;
using u64 = unsigned long long;
//std :: mt19937_64 rng {std :: chrono::steady_clock::now().time_since_epoch().count()};
constexpr int N = 2e5 + 10;
int f[5000][50][50];
bool check(int x) {
if (x % 400 == 0 || (x % 4 == 0 && x % 100 != 0)) {
return 1;
} else {
return 0;
}
}
int month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int sg(int y, int h, int d) {
if (y > 2024 || (y == 2024 && h > 8) || (y == 2024 && h == 8 && d > 1)) {
return 0;
}
auto &v = f[y][d][h];
if (v != -1) {
return v;
}
std :: unordered_set<int> S;
int ok = check(y);
// + 1 Day
int nowd;
if (h == 2) {
nowd = month[h] + ok;
} else {
nowd = month[h];
}
if (d + 1 <= nowd) {
S.insert(sg(y, h, d + 1));
} else {
if (h + 1 <= 12) {
S.insert(sg(y, h + 1, 1));
} else {
S.insert(sg(y + 1, 1, 1));
}
}
// + 1 month
if (h + 1 <= 12) {
S.insert(sg(y, h + 1, d));
} else {
S.insert(sg(y + 1, 1, d));
}
for (int i = 0; ; i ++)
if (!S.count(i))
return v = i;
}
void solve() {
int X, Y, Z;
std :: cin >> X >> Y >> Z;
int res = sg(X, Y, Z);
if (res) {
std :: cout << "YES\n";
} else {
std :: cout << "NO\n";
}
return;
}
int main() {
std :: ios :: sync_with_stdio(false);
std :: cin.tie(0);
// init();
memset(f, -1, sizeof f);
f[2024][8][1] = 0;
int T = 1;
std :: cin >> T;
while (T --) {
solve();
}
return 0;
}
B.学生分组
模拟&思维.
计算每个学生个数变到[L,R]的需要的次数,根据题意进行模拟即可.
#include <bits/stdc++.h>
using u32 = unsigned;
using i64 = long long;
using u64 = unsigned long long;
//std :: mt19937_64 rng {std :: chrono::steady_clock::now().time_since_epoch().count()};
constexpr int N = 2e5 + 10;
void solve() {
int n;
std :: cin >> n;
std :: vector<i64> a(n + 1);
for (int i = 1; i <= n; i ++) {
std :: cin >> a[i];
}
i64 L, R;
std :: cin >> L >> R;
if (n == 1) {
if (a[1] >= L && a[1] <= R) {
std :: cout << 0 << "\n";
} else {
std :: cout << -1 << "\n";
}
return;
}
i64 l = 0, r = 0;
i64 canl = 0, canr = 0;
for (int i = 1; i <= n; i ++) {
if (a[i] < L) {
l += (L - a[i]);
}
if (a[i] > R) {
r += (a[i] - R);
}
if (a[i] <= R) canl += (R - std :: max(L, a[i]));
if (a[i] >= L) canr += (std :: min(R, a[i]) - L);
}
// std :: cout << l << " " << r << "\n";
if (l + canl < r || r + canr < l) {
std :: cout << -1 << "\n";
return;
}
std :: cout << std :: max<i64>(l, r) << "\n";
return;
}
int main() {
std :: ios :: sync_with_stdio(false);
std :: cin.tie(0);
int T = 1;
//std :: cin >> T;
while (T --) {
solve();
}
return 0;
}
C. 小美想收集
二分答案 + 染色法判断二分图。
#include <bits/stdc++.h>
using u32 = unsigned;
using i64 = long long;
using u64 = unsigned long long;
using PII = std :: pair<int, int>;
//std :: mt19937_64 rng {std :: chrono::steady_clock::now().time_since_epoch().count()};
constexpr int N = 1e5 + 10;
std :: vector<PII> g[N];
int n, m;
int color[N];
// 染色法判断是否为二分图
bool dfs(int u, int c, int mid) {
color[u] = c;
for (auto [v, w] : g[u]) {
if (w <= mid)
continue;
if (color[v] == c)
return false;
if (!color[v] && !dfs(v, 3 - c, mid))
return false;
}
return true;
}
bool check(int mid) {
memset(color, 0, sizeof color);
for (int i = 1; i <= n; ++i) {
if (!color[i] && !dfs(i, 1, mid))
return false;
}
return true;
}
void solve() {
std :: cin >> n >> m;
std :: vector<std :: tuple<int, int, int> > a;
for (int i = 0; i < m; i ++) {
int u, v, w;
std :: cin >> u >> v >> w;
g[u].push_back({v, w});
g[v].push_back({u, w});
}
int l = 1, r = 1e6;
while (l < r) {
int mid = (l + r) >> 1;
if (check(mid)) {
r = mid;
} else {
l = mid + 1;
}
}
std :: cout << l << "\n";
return;
}
int main() {
std :: ios :: sync_with_stdio(false);
std :: cin.tie(0);
int T = 1;
//std :: cin >> T;
while (T --) {
solve();
}
return 0;
}
另有二分答案 + 并查集的做法。
#include <bits/stdc++.h>
using u32 = unsigned;
using i64 = long long;
using u64 = unsigned long long;
//std :: mt19937_64 rng {std :: chrono::steady_clock::now().time_since_epoch().count()};
constexpr int N = 1e5 + 10;
std :: vector<int> g[N];
int n, m;
std :: vector<int> p(N);
int find(int x) {
if (p[x] != x) {
p[x] = find(p[x]);
}
return p[x];
}
void solve() {
std :: cin >> n >> m;
std :: vector<std :: tuple<int, int, int> > a;
for (int i = 0; i < m; i ++) {
int u, v, w;
std :: cin >> u >> v >> w;
a.push_back({u, v, w});
}
auto check = [&](int mid) -> int {
iota(p.begin(), p.begin() + n + n + 1, 0);
for (auto [a, b, c] : a) {
if (c > mid) {
int pa = find(a), pb = find(b);
if (pa == pb) return false;
p[find(a + n)] = find(b);
p[find(b + n)] = find(a);
}
}
return true;
};
int l = 1, r = 1e6;
while (l < r) {
int mid = (l + r) >> 1;
if (check(mid)) {
r = mid;
} else {
l = mid + 1;
}
}
std :: cout << l << "\n";
return;
}
int main() {
std :: ios :: sync_with_stdio(false);
std :: cin.tie(0);
int T = 1;
//std :: cin >> T;
while (T --) {
solve();
}
return 0;
}
D. 区间问题1
线段树模板题
#include <bits/stdc++.h>
const int N = 1e5 + 10;
int a[N];
int n, q;
struct Tree
{
int l, r;
int sum, add;
} tr[N << 2];
void pushup(Tree &root, Tree &li, Tree &ri)
{
root.sum = li.sum + ri.sum;
}
void pushup(int u) //上传更新
{
pushup(tr[u], tr[u << 1], tr[u << 1 | 1]);
}
void build(int u, int l, int r) //建树
{
tr[u].l = l, tr[u].r = r;
if(l == r)
{
tr[u].sum = a[l];
return;
}
int mid = l + r >> 1;
build(u << 1, l, mid);
build(u << 1 | 1, mid + 1, r);
pushup(u);
}
void pushdown(Tree &root, Tree &li, Tree &ri)
{
li.add += root.add;
ri.add += root.add;
li.sum += (li.r - li.l + 1) * root.add;
ri.sum += (ri.r - ri.l + 1) * root.add;
root.add = 0;
}
void pushdown(int u)
{
pushdown(tr[u], tr[u << 1], tr[u << 1 | 1]);
}
void modify(int u, int l, int r, int k)
{
if(tr[u].l >= l && tr[u].r <= r)
{
tr[u].sum += (tr[u].r - tr[u].l + 1) * k;
tr[u].add += k;
return;
}
pushdown(u);
int mid = (tr[u].l + tr[u].r) >> 1;
if(mid >= l) modify(u << 1, l, r, k);
if(mid < r) modify(u << 1 | 1, l, r, k);
pushup(u);
}
int query(int u, int l, int r)
{
if(tr[u].l >= l && tr[u].r <= r) return tr[u].sum;
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
int res = 0;
if(mid >= l) res += query(u << 1, l, r);
if(mid < r) res += query(u << 1 | 1, l, r);
return res;
}
int main()
{
std :: cin >> n;
for (int i = 1; i <= n; i ++) {
std :: cin >> a[i];
}
build(1, 1, n);
std :: cin >> q;
while(q--)
{
int op;
std :: cin >> op;
if(op == 1)
{
int x, y, d;
std :: cin >> x >> y >> d ;
modify(1, x, y, d);
}
else
{
int x;
std :: cin >> x;
std :: cout << query(1, x, x) << "\n";
}
}
}
E. 哥德巴赫猜想
分解质因数,暴力枚举即可
#include <bits/stdc++.h>
using u32 = unsigned;
using i64 = long long;
using u64 = unsigned long long;
//std :: mt19937_64 rng {std :: chrono::steady_clock::now().time_since_epoch().count()};
constexpr int N = 2e5 + 10;
int primes[N], cnt;
int st[N];
void get_primes(int n)
{
for (int i = 2; i <= n; i ++ )
{
if (!st[i]) primes[cnt ++ ] = i;
for (int j = 0; primes[j] <= n / i; j ++ )
{
st[primes[j] * i] = true;
if (i % primes[j] == 0) break;
}
}
}
void solve() {
int n;
std :: cin >> n;
for (int i = 0; i < cnt; i ++) {
for (int j = 0; j < cnt; j ++) {
int sum = primes[i] + primes[j];
if (n - sum >= 2 && !st[n - sum]) {
std :: cout << primes[i] << " " << primes[j] << " " << (n - sum) << "\n";
return;
}
}
}
std :: cout << -1 << "\n";
return;
}
int main() {
get_primes(50010);
std :: ios :: sync_with_stdio(false);
std :: cin.tie(0);
int T = 1;
std :: cin >> T;
while (T --) {
solve();
}
return 0;
}
F. 小美想跑步
题意就是求1号点到其余所有节点的最短路的和 + 其余所有节点到1号节点的最短路的和
Dijkstra求最短路
首先求1号点到其余所有节点的最短路的和:只需按照题意建图跑一遍Dijkstra即可求出.
接下来如何求出其余所有节点到1号节点的最短路的和?
只需要将题目给定的有向边,反过来建图,在跑一遍Dijkstra即可解决问题。
#include <bits/stdc++.h>
using u32 = unsigned;
using i64 = long long;
using u64 = unsigned long long;
//std :: mt19937_64 rng {std :: chrono::steady_clock::now().time_since_epoch().count()};
constexpr int N = 2e5 + 10;
using PII = std :: pair<i64, int>;
std :: vector<PII> g[N];
int n, m;
i64 ans = 0;
void dijkstra() {
std :: vector<i64> d(n + 1, 1e18);
std :: vector<int> st(n + 1);
std :: priority_queue<PII, std :: vector<PII>, std :: greater<PII> > q;
q.push({0, 1});
d[1] = 0;
while (q.size()) {
auto u = q.top().second;
q.pop();
if (st[u]) {
continue;
}
st[u] = 1;
for (auto [v, w] : g[u]) {
if (d[v] > d[u] + w) {
d[v] = d[u] + w;
q.push({d[v], v});
}
}
}
for (int i = 2; i <= n; i ++) {
ans += d[i];
}
}
void solve() {
std :: cin >> n >> m;
std :: vector<std :: tuple<int, int, int> > a;
for (int i = 0; i < m; i ++) {
int u, v, w;
std :: cin >> u >> v >> w;
a.push_back({u, v, w});
g[u].push_back({v, w});
}
dijkstra();
for (int i = 1; i <= n; i ++) {
g[i].clear();
}
for (auto [u, v, w] : a) {
g[v].push_back({u, w});
}
dijkstra();
std :: cout << ans << "\n";
return;
}
int main() {
std :: ios :: sync_with_stdio(false);
std :: cin.tie(0);
int T = 1;
//std :: cin >> T;
while (T --) {
solve();
}
return 0;
}
G.爬楼梯
经典线性Dp
+
+
#include <bits/stdc++.h>
using u32 = unsigned;
using i64 = long long;
using u64 = unsigned long long;
//std :: mt19937_64 rng {std :: chrono::steady_clock::now().time_since_epoch().count()};
constexpr int N = 2e5 + 10;
const int mod = 1e9 + 7;
void solve() {
int n;
std :: cin >> n;
std :: vector<int> dp(n + 1);
dp[1] = 1, dp[2] = 2, dp[3] = 4;
for (int i = 4; i <= n; i++) {
dp[i] = (1ll * dp[i - 1] + dp[i - 2] + dp[i - 3]) % mod;
}
std :: cout << dp[n] << "\n";
return;
}
int main() {
std :: ios :: sync_with_stdio(false);
std :: cin.tie(0);
int T = 1;
//std :: cin >> T;
while (T --) {
solve();
}
return 0;
}
H.区间问题2
ST表 模板题 求区间最大值
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
const int N = 1e6 + 10;
int n;
int f[N][22];
int main()
{
scanf("%d", &n);
std :: vector<int> a(n + 1);
for(int i = 1; i <= n; i ++) std :: cin >> a[i];
for(int i = 0; i < 22; i ++)
{
for(int j = 1; j + (1 << i) - 1 <= n; j ++)
{
if(!i) f[j][i] = a[j];
else f[j][i] = std :: max(f[j][i - 1], f[j + (1 << i - 1)][i - 1]);
}
}
int q;
scanf("%d", &q);
while(q --)
{
int l, r;
scanf("%d%d", &l, &r);
int k = (r - l + 1);
int j = log2(k);
printf("%d\n", std :: max(f[l][j], f[r - (1 << j) + 1][j]));
}
return 0;
}
I.小美想打音游
注:本人做法略偏,使用三分找出极小值,最后求出答案,实际本题可以使用较为简单的前缀和做法\
可以观察本题其实就是需要求一个X,使得 尽可能小,所以我使用三分找出了这个X;
最后答案就是 + 1;
#include <bits/stdc++.h>
using u32 = unsigned;
using i64 = long long;
using u64 = unsigned long long;
//std :: mt19937_64 rng {std :: chrono::steady_clock::now().time_since_epoch().count()};
constexpr int N = 2e5 + 10;
int n;
void solve() {
std :: cin >> n;
std :: vector<int> c(n + 1);
for (int i = 1; i <= n; i ++) {
std :: cin >> c[i];
}
auto calc = [&](int x) -> i64 {
i64 sum = 0;
for (int i = 1; i <= n; i ++) {
sum += abs(c[i] - x);
}
return sum;
};
int l = 0, r = 1e6;
while (l < r) {
int midl = l + (r - l) / 3, midr = r - (r - l) / 3;
if (calc(midl) < calc(midr)) r = midr - 1;
else l = midl + 1;
}
std :: cout << calc(l) + 1 << "\n";
return;
}
int main() {
std :: ios :: sync_with_stdio(false);
std :: cin.tie(0);
int T = 1;
//std :: cin >> T;
while (T --) {
solve();
}
return 0;
}
J 平方根
签到题
#include <bits/stdc++.h>
using u32 = unsigned;
using i64 = long long;
using u64 = unsigned long long;
//std :: mt19937_64 rng {std :: chrono::steady_clock::now().time_since_epoch().count()};
constexpr int N = 2e5 + 10;
void solve() {
i64 n;
std :: cin >> n;
std :: cout << (i64)sqrt(n) << "\n";
return;
}
int main() {
std :: ios :: sync_with_stdio(false);
std :: cin.tie(0);
int T = 1;
std :: cin >> T;
while (T --) {
solve();
}
return 0;
}
K 小美想游泳
二分 + Dijkstra 每次check,跑dijkstra,同时以mid为上限,如果某条边波浪值大于mid则不能通过此边
#include <bits/stdc++.h>
using u32 = unsigned;
using i64 = long long;
using u64 = unsigned long long;
//std :: mt19937_64 rng {std :: chrono::steady_clock::now().time_since_epoch().count()};
constexpr int N = 1e4 + 10;
using PII = std :: pair<int, int>;
std :: vector<PII> g[N];
int n, m, s, t;
int dijkstra(int x) {
std :: vector<int> st(n + 1);
std :: vector<int> d(n + 1, 1e9);
std :: priority_queue<PII, std :: vector<PII>, std :: greater<PII> > q;
q.push({0, s});
d[s] = 0;
while (q.size()) {
auto u = q.top().second;
q.pop();
if (st[u]) {
continue;
}
st[u] = 1;
for (auto [v, w] : g[u]) {
if (w > x) {
continue;
}
if (d[v] > d[u] + 1) {
d[v] = d[u] + 1;
q.push({d[v], v});
}
}
}
return d[t];
}
bool check(int x) {
if (dijkstra(x) == (int)1e9) {
return false;
}
return true;
}
void solve() {
std :: cin >> n >> m;
for (int i = 0; i < m; i ++) {
int u, v, a;
std :: cin >> u >> v >> a;
g[u].push_back({v, a});
g[v].push_back({u, a});
}
std :: cin >> s >> t;
int l = 1, r = 1e4;
while (l < r) {
int mid = (l + r >> 1);
if(check(mid)) r = mid;
else l = mid + 1;
}
std :: cout << l << "\n";
return;
}
int main() {
std :: ios :: sync_with_stdio(false);
std :: cin.tie(0);
int T = 1;
//std :: cin >> T;
while (T --) {
solve();
}
return 0;
}