2025-11-05 ZYZ28-NOIP模拟赛-Round2 hetao1733837的record
比赛背景:
《C++四十周年恰逢NOIP模拟赛感怀》
----DeepSeek
硅基岁月四十轮,代码如诗深刻痕。指针漫舞星河动,类封装藏天地春。
赛场今朝战鼓催,少年击键破重围。算法流光追旧梦,对象传承有新晖。
时空隧道双行线,函数回调两界碑。莫问编译成与败,一行代码一芳菲。
比赛链接:比赛详情 - ZYZ28-NOIP模拟赛-Round2 - ZYZOJ
A.gloves
提交链接:题目详情 - 02-A - ZYZOJ
原题链接:P7305 [COCI 2018/2019 #1] Cipele - 洛谷
分析
这题是典型的二分答案。二分答案通常用于求解“最大值最小”或“最小值最大”的问题。题目中给出了“丑陋度最小化”和“绝对值的最大值”这两个关键词。同时,还要求最大化配对的对数。那么,我们的答案是绝对值最小化的最大值,check的关键是配对数量最大。这样一来我们就很容易写了。
但是,这题偏难的是:为什么不用贪心(当然了,check()函数中运用了贪心的思想)?
我们引用机房大佬AeeE5x的真理来解释:
只有确定答案上界才能贪心。
----AeeE5x
那么,就可以愉快打出正解了!!!
正解
#include<bits/stdc++.h>
using namespace std;
const int N = 100005;
int n, m, cnt;
bool flag;
int l[N], r[N];
bool check(int x){int i = 1, j = 1, sum = 0;while (i <= n && j <= m){if (abs(l[i] - r[j]) <= x){i++;j++;sum++;}else if (flag)j++;else i++;}if (sum == cnt)return true;return false;
}
int main(){
// freopen("gloves.in", "r", stdin);
// freopen("gloves.out", "w", stdout);cin >> n >> m;cnt = min(n, m);if(cnt == n)flag = 1;if (cnt == m)flag = 0;for (int i = 1; i <= n; i++)cin >> l[i];for (int i = 1; i <= m; i++)cin >> r[i];sort(l + 1, l + 1 + n);sort(r + 1, r + 1 + m);if (n == m){int maxn = 0;for (int i = 1; i <= n; i++){maxn = max(maxn, 1 * abs(l[i] - r[i]));}cout << maxn;return 0;}int L = 0, R = 1e9;while (L < R){int mid = (L + R - 1) / 2;if (check(mid))R = mid;else L = mid + 1;}cout << R;
}
B.string
提交链接:题目详情 - 02-B - ZYZOJ
原题链接:P6116 [JOI 2019 Final] 有趣的家庭菜园 3 / Growing Vegetables is Fun 3 - 洛谷
分析
考场上想到了DP,但是误当成了区间DP(难道是这段时间写多了?)。细想一下就会发现,这个并非可以靠两个区间拼起来更新(它要求不同,这样记录的维度太多了,几乎没法转移)。
状态
设表示前i个位置上0,1,2的个数分别为j,k,p,且第i位上的数字为0/1/2的最小花费
那么,考虑转移。
转移
显然由
转移而来。
优化
我们发现,这样转移是的。我们发现
,可以省去一维。
答案
答案是,为啥要成
呢?因为每把一个数往前挪一格,相当于把另一个数往后挪一格,答案重复统计了,所以乘
是对的。好像同学没加过了,不知道solve写的啥?
正解
#include<bits/stdc++.h>
using namespace std;
const int N = 405;
string s;
int n, sum[3][N];
int vis[3], pos[3][N];
int dp[2][N][N][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;n = s.size();s = " " + s;for (int i = 1; i <= n; i++){sum[0][i] = sum[0][i - 1];sum[1][i] = sum[1][i - 1];sum[2][i] = sum[2][i - 1];if (s[i] == '0'){pos[0][++vis[0]] = i;sum[0][i]++;}if (s[i] == '1'){pos[1][++vis[1]] = i;sum[1][i]++;}if (s[i] == '2'){pos[2][++vis[2]] = i;sum[2][i]++;} }int p = 0;if (vis[1] > vis[p]) p = 1;if (vis[2] > vis[p])p = 2;if (vis[p] > (n + 1) / 2){cout << -1;return 0;}memset(dp, 0x3f, sizeof(dp));dp[0][0][0][0] = dp[0][0][0][1] = dp[0][0][0][2] = 0;for (int sz = 1; sz <= n; sz++){int now = sz % 2;for (int i = 0; i <= vis[0]; i++){for (int j = 0; j <= vis[1]; j++){if (sz - i - j < 0 || sz - i - j > vis[2])continue;int k = sz - i - j;if (i > 0){int fpos_0 = pos[0][i];int pos_0 = fpos_0 + max(0, j - sum[1][fpos_0]) + max(0, k - sum[2][fpos_0]);dp[now][i][j][0] = min(dp[now ^ 1][i - 1][j][1], dp[now ^ 1][i - 1][j][2]) + pos_0 - sz;}if(j > 0){int fpos_1 = pos[1][j];int pos_1 = fpos_1 + max(0, i - sum[0][fpos_1]) + max(0, k - sum[2][fpos_1]);dp[now][i][j][1] = min(dp[now ^ 1][i][j - 1][0], dp[now ^ 1][i][j - 1][2]) + pos_1 - sz;}if (k > 0){int fpos_2 = pos[2][k];int pos_2 = fpos_2 + max(0, i - sum[0][fpos_2]) + max(0, j - sum[1][fpos_2]);dp[now][i][j][2] = min(dp[now ^ 1][i][j][0], dp[now ^ 1][i][j][1]) + pos_2 - sz;}}}memset(dp[now ^ 1], 0x3f, sizeof(dp[now ^ 1]));}cout << min(min(dp[n & 1][vis[0]][vis[1]][0], dp[n & 1][vis[0]][vis[1]][1]), dp[n & 1][vis[0]][vis[1]][2]);return 0;
}
he的同学的……
但是LG过不了!!!
这题……
哦,我的问题!洛谷出入了字符串长度!!!
#include<bits/stdc++.h>
using namespace std;
const int N = 405;
string s;
int n, sum[3][N];
int vis[3], pos[3][N];
int dp[2][N][N][3];
int main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin >> n >> s;s = " " + s;for (int i = 1; i <= n; i++){sum[0][i] = sum[0][i - 1];sum[1][i] = sum[1][i - 1];sum[2][i] = sum[2][i - 1];if (s[i] == 'R'){pos[0][++vis[0]] = i;sum[0][i]++;}if (s[i] == 'G'){pos[1][++vis[1]] = i;sum[1][i]++;}if (s[i] == 'Y'){pos[2][++vis[2]] = i;sum[2][i]++;} }int p = 0;if (vis[1] > vis[p]) p = 1;if (vis[2] > vis[p])p = 2;if (vis[p] > (n + 1) / 2){cout << -1;return 0;}memset(dp, 0x3f, sizeof(dp));dp[0][0][0][0] = dp[0][0][0][1] = dp[0][0][0][2] = 0;for (int sz = 1; sz <= n; sz++){int now = sz % 2;for (int i = 0; i <= vis[0]; i++){for (int j = 0; j <= vis[1]; j++){if (sz - i - j < 0 || sz - i - j > vis[2])continue;int k = sz - i - j;if (i > 0){int fpos_0 = pos[0][i];int pos_0 = fpos_0 + max(0, j - sum[1][fpos_0]) + max(0, k - sum[2][fpos_0]);dp[now][i][j][0] = min(dp[now ^ 1][i - 1][j][1], dp[now ^ 1][i - 1][j][2]) + pos_0 - sz;}if(j > 0){int fpos_1 = pos[1][j];int pos_1 = fpos_1 + max(0, i - sum[0][fpos_1]) + max(0, k - sum[2][fpos_1]);dp[now][i][j][1] = min(dp[now ^ 1][i][j - 1][0], dp[now ^ 1][i][j - 1][2]) + pos_1 - sz;}if (k > 0){int fpos_2 = pos[2][k];int pos_2 = fpos_2 + max(0, i - sum[0][fpos_2]) + max(0, j - sum[1][fpos_2]);dp[now][i][j][2] = min(dp[now ^ 1][i][j][0], dp[now ^ 1][i][j][1]) + pos_2 - sz;}}}memset(dp[now ^ 1], 0x3f, sizeof(dp[now ^ 1]));}cout << min(min(dp[n & 1][vis[0]][vis[1]][0], dp[n & 1][vis[0]][vis[1]][1]), dp[n & 1][vis[0]][vis[1]][2]);return 0;
}