[赛记] 多校A层冲刺NOIP2024模拟赛06
小 Z 的手套(gloves)100pts
最大值最小,考虑二分答案;
首先排序,然后每次找出数量较少的那个数组中的每个数
因为已经升序排序,所以可以双指针维护,当然也可以 lower_bound
,但是多个
时间复杂度;
点击查看代码
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
int n, m;
int a[500005], b[500005];
int vis[500005], vi[500005];
bool ck(int x) {
for (int i = 1; i <= max(n, m); i++) {
vis[i] = 0;
vi[i] = 0;
}
if (n < m) {
int now = lower_bound(b + 1, b + 1 + m, a[1] - x) - b;
for (int i = 1; i <= n; i++) {
int lpos = lower_bound(b + 1, b + 1 + m, a[i] - x) - b;
if (lpos > m) return false;
if (now < lpos) now = lpos;
while(vis[now]) now++;
vis[now] = i;
}
for (int i = 1; i <= m; i++) {
if (vis[i]) {
vi[vis[i]] = true;
if (abs(a[vis[i]] - b[i]) > x) return false;
}
}
for (int i = 1; i <= n; i++) if (!vi[i]) return false;
return true;
} else {
int now = lower_bound(a + 1, a + 1 + n, b[1] - x) - a;
for (int i = 1; i <= m; i++) {
int lpos = lower_bound(a + 1, a + 1 + n, b[i] - x) - a;
if (lpos > n) return false;
if (now < lpos) now = lpos;
while(vis[now]) now++;
vis[now] = i;
}
for (int i = 1; i <= n; i++) {
if (vis[i]) {
vi[vis[i]] = true;
if (abs(b[vis[i]] - a[i]) > x) return false;
}
}
for (int i = 1; i <= m; i++) if (!vi[i]) return false;
return true;
}
}
int main() {
freopen("gloves.in", "r", stdin);
freopen("gloves.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
for (int i = 1; i <= m; i++) {
cin >> b[i];
}
sort(a + 1, a + 1 + n);
sort(b + 1, b + 1 + m);
int l = 0;
int r = 1000000000;
int ans = 0;
while(l <= r) {
int mid = (l + r) >> 1;
if (ck(mid)) {
ans = mid;
r = mid - 1;
} else {
l = mid + 1;
}
}
cout << ans;
return 0;
}
小 Z 的字符串(string)20pts
DP;
设
对于转移,发现肯定不会换同一个数,所以假设有转移
最后答案要除以
时间复杂度:
点击查看代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
int n;
char s[505];
int t[3][405];
int f[205][205][205][3];
int c[3];
int main() {
freopen("string.in", "r", stdin);
freopen("string.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> (s + 1);
n = strlen(s + 1);
for (int i = 1; i <= n; i++) {
t[s[i] - '0'][++c[s[i] - '0']] = i;
}
if (c[0] > (n + 1) / 2 || c[1] > (n + 1) / 2 || c[2] > (n + 1) / 2) {
cout << -1;
return 0;
}
memset(f, 0x3f, sizeof(f));
f[0][0][0][0] = f[0][0][0][1] = f[0][0][0][2] = 0;
for (int i = 0; i <= c[0]; i++) {
for (int j = 0; j <= c[1]; j++) {
for (int k = 0; k <= c[2]; k++) {
int p = i + j + k;
if (p == 0) continue;
if (i) f[i][j][k][0] = min(f[i - 1][j][k][1], f[i - 1][j][k][2]) + abs(p - t[0][i]);
if (j) f[i][j][k][1] = min(f[i][j - 1][k][0], f[i][j - 1][k][2]) + abs(p - t[1][j]);
if (k) f[i][j][k][2] = min(f[i][j][k - 1][0], f[i][j][k - 1][1]) + abs(p - t[2][k]);
}
}
}
cout << min({f[c[0]][c[1]][c[2]][0], f[c[0]][c[1]][c[2]][1], f[c[0]][c[1]][c[2]][2]}) / 2;
return 0;
}
一个真实的故事(truth)50pts
赛时打的
正解就是线段树;
维护三个东西:
-
答案;
-
从左边开始的1 ~ k 出现的位置;
-
从右边开始的1 ~ k 出现的位置;
这样合并的时候只需将左区间的2和右区间的3合并起来,然后双指针扫一下即可;
时间复杂度:
点击查看代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int n, k, m;
int a[500005];
int cnt[35];
pair<int, int> rem[75];
int rcnt;
namespace SEG{
inline int ls(int x) {
return x << 1;
}
inline int rs(int x) {
return x << 1 | 1;
}
struct sss{
int l, r, ans, lb[35], rb[35];
}tr[800005];
inline void push_up(int id) {
memset(cnt, 0, sizeof(cnt));
rcnt = 0;
for (int i = 1; i <= k; i++) {
rem[++rcnt] = {tr[ls(id)].rb[i], i};
rem[++rcnt] = {tr[rs(id)].lb[i], i};
}
sort(rem + 1, rem + 1 + rcnt);
int now = 0;
int an = 0x3f3f3f3f;
int pos = 1;
for (int i = 1; i <= rcnt; i++) {
if (rem[i].first) {
pos = i;
break;
}
}
int j = pos;
for (int i = pos; i <= rcnt; i++) {
if (!cnt[rem[i].second]) now++;
cnt[rem[i].second]++;
while(now == k) {
an = min(an, rem[i].first - rem[j].first + 1);
cnt[rem[j].second]--;
if (cnt[rem[j].second] == 0) now--;
j++;
}
}
tr[id].ans = min({an, tr[ls(id)].ans, tr[rs(id)].ans});
for (int i = 1; i <= k; i++) {
if (tr[ls(id)].lb[i]) tr[id].lb[i] = tr[ls(id)].lb[i];
else tr[id].lb[i] = tr[rs(id)].lb[i];
if (tr[rs(id)].rb[i]) tr[id].rb[i] = tr[rs(id)].rb[i];
else tr[id].rb[i] = tr[ls(id)].rb[i];
}
}
void bt(int id, int l, int r) {
tr[id].l = l;
tr[id].r = r;
tr[id].ans = 0x3f3f3f3f;
if (l == r) {
tr[id].lb[a[l]] = tr[id].rb[a[l]] = l;
if (k == 1) {
if (a[l] == k) tr[id].ans = 1;
}
return;
}
int mid = (l + r) >> 1;
bt(ls(id), l, mid);
bt(rs(id), mid + 1, r);
push_up(id);
}
void add(int id, int pos, int x) {
if (tr[id].l == tr[id].r) {
tr[id].ans = 0x3f3f3f3f;
if (k == 1) {
if (a[tr[id].l] == k) tr[id].ans = 1;
}
tr[id].lb[x] = tr[id].rb[x] = 0;
tr[id].lb[a[tr[id].l]] = tr[id].rb[a[tr[id].l]] = tr[id].l;
return;
}
int mid = (tr[id].l + tr[id].r) >> 1;
if (pos <= mid) add(ls(id), pos, x);
else add(rs(id), pos, x);
push_up(id);
}
}
using namespace SEG;
int main() {
freopen("truth.in", "r", stdin);
freopen("truth.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> k >> m;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
bt(1, 1, n);
int s, p, v;
for (int i = 1; i <= m; i++) {
cin >> s;
if (s == 1) {
cin >> p >> v;
int x = a[p];
a[p] = v;
add(1, p, x);
}
if (s == 2) {
if (tr[1].ans == 0x3f3f3f3f) cout << -1 << '\n';
else cout << tr[1].ans << '\n';
}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具