20260530模拟赛总结
分数总结
| 题目 | 期望分数 | 实际分数 | 挂分分数 |
|---|---|---|---|
| A - 音乐节拍器 | 100pts | 100pts | 0pts |
| B - 连续打卡 | 100pts | 100pts | 0pts |
| C - 抓取卡牌 | 100pts | 55pts | 45pts |
| D - 子树染色 | 100pts | 100pts | 0pts |
| E - 勇闯迷宫 | I don't know | 40pts | I don't know |
| F - 足球训练 | 30pts | 30pts | 0pts |
题目解析
C - 抓取卡牌
眼睛不知道干什么去了,\(0 \le X,a_i \le 2 \times 10^5\),注意,有 \(0\)!
时间复杂度:\(O(n\log n)\)。
空间复杂度:\(O(n)\)。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define db double
#define inf (1 << 30)
#define lnf (1LL << 60)
#define all(x) (x).begin(), (x).end()
typedef pair<int, int> PII;
constexpr int N = 2e5 + 7;
constexpr int P = 998244353;
int n, x, v[N], a[N];
struct Node {
int val, limit, k;
bool operator < (const Node &A) const {
return val / k < A.val / A.k;
}
};
priority_queue<Node> q;
int main() {
scanf("%d%d", &n, &x);
for (int i = 1; i <= n; i++) scanf("%d", &v[i]);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
for (int i = 1; i <= n; i++) {
if (a[i])
q.push({v[i], a[i], 1});
}
ll ans = 0;
while (x--) {
auto t = q.top();
q.pop();
ans += t.val / t.k;
if (t.k + 1 > t.limit) continue;
q.push({t.val, t.limit, t.k + 1});
}
printf("%lld\n", ans);
return 0;
}
E - 勇闯迷宫
关于 SPFA,他死了。
首先 \(90pts\) 做法,用 Dijkstra 来做最短路。
但是会 TLE,我们发现只有 \(0\) 和 \(1\),所以可以 01BFS。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define db double
#define inf (1 << 30)
#define lnf (1LL << 60)
#define all(x) (x).begin(), (x).end()
typedef pair<int, int> PII;
constexpr int N = 300 + 7, MAXP = 100 + 7;
constexpr int P = 998244353;
constexpr int dx[] = {-1, 0, 0, 1, 0};
constexpr int dy[] = {0, -1, 1, 0, 0};
struct Node {
int x, y, p;
bool use;
};
int n, m, p, col[N][N];
int sx, sy, ex, ey;
char s[N][N];
ll dis[N][N][MAXP][2];
bool vis[N][N][MAXP][2];
deque<Node> dq;
void bfs() {
memset(dis, 0x3f, sizeof(dis));
dis[sx][sy][0][0] = 0;
dq.push_back({sx, sy, 0, false});
while (!dq.empty()) {
auto u = dq.front();
dq.pop_front();
if (vis[u.x][u.y][u.p][u.use]) continue;
vis[u.x][u.y][u.p][u.use] = true;
if (!u.use) {
for (int l = 0; l < p; l++) {
int np = l, cost = 1;
if (dis[u.x][u.y][u.p][u.use] + cost < dis[u.x][u.y][np][true]) {
dis[u.x][u.y][np][true] = dis[u.x][u.y][u.p][u.use] + cost;
Node v = {u.x, u.y, np, true};
dq.push_back(v);
}
}
}
for (int i = 0; i < 5; i++) {
int nx = u.x + dx[i];
int ny = u.y + dy[i];
if (nx < 1 || nx > n || ny < 1 || ny > m) continue;
if (s[nx][ny] == '#') continue;
int np = (u.p + 1) % p;
int cost = ((col[nx][ny] == u.p) ? 0 : 1);
if (dis[u.x][u.y][u.p][u.use] + cost < dis[nx][ny][np][u.use]) {
dis[nx][ny][np][u.use] = dis[u.x][u.y][u.p][u.use] + cost;
Node v = {nx, ny, np, u.use};
if (cost == 0) dq.push_front(v);
else dq.push_back(v);
}
}
}
ll minv = lnf;
for (int i = 0; i < p; i++)
for (int u = 0; u < 2; u++)
minv = min(minv, dis[ex][ey][i][u]);
printf("%lld\n", minv == lnf ? -1 : minv);
}
int main() {
scanf("%d%d%d", &n, &m, &p);
for (int i = 1; i <= n; i++) {
scanf("%s", s[i] + 1);
for (int j = 1; j <= m; j++) {
if (s[i][j] == 'S') {
sx = i, sy = j;
}
if (s[i][j] == 'T') {
ex = i, ey = j;
}
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
scanf("%d", &col[i][j]);
}
}
bfs();
return 0;
}
F - 足球训练
简述题意:给定 \(n\) 个数对 \((a,b)\),每次可以将一个数对变成 \((a+b,b)\),求最后 \(a\) 的乘积最大是多少。
\(30\) 分做法:可以简单 DP。
先不考虑太多,设式子为 \(a_1 \times a_2 \times C\)。
\(C\) 为其他的乘积。
如果是加上 \(a_1\) 更好,式子就变成了 \((a_1+b_1)\times a_2 \times C > (a_2+b_2)\times a_1 \times C\)。
\(C\) 就约掉了。
然后用我们小学二年级就学过的交叉相乘得到
\[\dfrac{a_1+b_1}{a_1} > \dfrac{a_2+b_2}{a_2}
\]
然后转换成带分数得到
\[1 + \dfrac{b_1}{a_1} > 1 + \dfrac{b_2}{a_2}
\]
然后就变成了
\[\dfrac{b_1}{a_1} > \dfrac{b_2}{a_2}
\]
所以说,想让 \(\dfrac{b}{a}\) 尽可能大。
\(60\) 分做法:可以维护一个堆,让 \(\dfrac{b}{a}\) 尽可能大。
其实 \(\dfrac{b}{a}\) 和 \(\dfrac{a}{b}\) 是等价的。
我们可以二分 \(\min(\dfrac{a}{b})\) 的最大值。
然后,就找到他们之间的差值,判断是否大于 \(m\) 就好了。
\(100\) 分做法:像刚刚说的二分,然后剩下的按照 \(60\) 分做法的做,可以证明,\(m\) 一定小于等于 \(n\),因为如果大于的话,一定不是最优解。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define int long long
#define ull unsigned long long
#define db double
#define inf (1 << 30)
#define lnf (1LL << 60)
#define all(x) (x).begin(), (x).end()
typedef pair<int, int> PII;
constexpr int N = 100000 + 7, MAXN = 3000 + 7;
constexpr int P = 998244353;
int n, m, a[N], b[N];
bool check(double mid) {
int res = 0;
for (int i = 1; i <= n; i++) {
double v = 1.0 * a[i] / b[i];
int cur = max(0.0, ceil(mid - v));
res += cur;
}
return res <= m;
}
struct Node {
int x, y, id;
bool operator < (const Node &A) const {
int nx = A.x, ny = A.y;
return nx * y < x * ny;
}
};
signed main() {
scanf("%lld%lld", &n, &m);
for (int i = 1; i <= n; i++) scanf("%lld%lld", &a[i], &b[i]);
double L = 0, R = 1e14;
for (int i = 1; i <= 100; i++) {
double mid = (L + R) / 2;
if (check(mid)) L = mid;
else R = mid;
}
priority_queue<Node> q;
__int128 ans = 1;
for (int i = 1; i <= n; i++) {
double v = 1.0 * a[i] / b[i];
int cur = max(0.0, ceil(L - v));
a[i] += 1LL * cur * b[i];
q.push({a[i], b[i], i});
m -= cur;
}
assert(m <= n);
// printf("%lf %lf\n", L, R);
while (m--) {
auto u = q.top();
q.pop();
a[u.id] += u.y;
q.push({a[u.id], u.y, u.id});
}
for (int i = 1; i <= n; i++) ans *= a[i], ans %= P;
printf("%lld\n", (ll)ans);
return 0;
}

浙公网安备 33010602011771号