2025-11-03 ZYZ28-NOIP模拟赛-Round1 hetao1733837的record
比赛链接:比赛详情 - ZYZ28-NOIP模拟赛-Round1 - ZYZOJ
比赛背景:
《四重奏》
指尖落在《piano》黑白键上,
 生命本就是明暗交错的乐章。
 我在晨光中调音,在暮色里弹奏,
 等待一个能听懂所有沉默的知音。
世界是流动的《rgb》,
 红是炽热的心跳,蓝是深沉的守望,绿是蔓延的希望。
 我们都在自己的色谱里寻找坐标,
 直到某天,你的光折射进我的波长。
那时才明白,所有的相遇都是《rescue》,
 不是谁拯救谁,而是两颗星找到了正确的轨道。
 在浩瀚宇宙里,我们互为方向,
 每一次靠近,都是对孤独的温柔抵抗。
从此踏上共同的《path》,
 不必问终点是花海还是荒野。
 脚印重叠处,时间开出永恒的花,
 而路,在每一步选择中无限延伸。
T1.piano
提交链接:ZYZOJ P5998 piano
原题链接:https://www.luogu.com.cn/problem/P7799
题面
样例
#input1:
5
1 2 0 3 1
#output1:
3
1#input2:
7 
2 1 -6 -2 1 6 10
#output2:
5
4 
分析
错误点
对于映射理解不到位。
正解
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1000005;
int n, a[N];
int sum[N];
map<int, int> mp;
signed main(){freopen("piano.in", "r", stdin);freopen("piano.out", "w", stdout);cin >> n;int base = 0;for (int i = 1; i <= n; i++){cin >> a[i];if (i == 1){sum[i] = 0;}else{if (a[i] > a[i - 1])sum[i] = sum[i - 1] + 1;if (a[i] < a[i - 1])sum[i] = sum[i - 1] - 1;if (a[i] == a[i - 1])sum[i] = sum[i - 1];}if (sum[i] == 0){if (a[i] == a[1])base++;}else{if ((a[i] - a[1]) % sum[i] == 0)mp[(a[i] - a[1]) / sum[i]]++;}}int ans = 0;int maxn = 0;for (auto tmp : mp){int k = tmp.first, cnt = tmp.second;if (cnt > maxn && k >= 0){maxn = cnt;ans = k;}}cout << base + maxn << '\n' << ans;
} 
T2.rgb
提交链接:ZYZOJ P5999 rgb
原题链接:https://www.luogu.com.cn/problem/P6441
题面
小Z有N支彩笔,每支笔有三个属性值。第i支笔和第j支笔的Difference值等于
,而Colorfulness值等于所选笔中Difference值的最大值。
小Z需要从中选出K支笔使得Colorfulness值尽可能小,输出最小的Colorfulness的值。
难度预估:黄
样例
#input1:
2 2
1 3 2
2 6 4
#output1:
3
#input2:
5 3
6 6 4
6 2 7
3 1 3
4 1 5
6 2 6
#output2:
2 
分析
首先确定这题的算法,思想及实现。
算法自然是二分答案——最大值最小。
思想——降维,三维RGB不好想,那我换成两维会好很多。
实现——三位前缀和。
这是什么样的逻辑关系呢?
首先,n和k都是1e5级别的,强制或者
,但是r[i],g[i],b[i]都是小于等于255的,可以做
,所以依次为主元,做枚举。
我们考虑降维,先求,绝对值不好看,我们钦定
,即可去掉绝对值,得出:
。那么,我们把R作为横轴,G作为纵轴,即可得出一个平面直角坐标系,我们只是用第一象限。将
看作四个值,即有
和
。使得以这两个点为右上端点和左下端点的矩形(可以证明是正方形,因为取max只有一个)中恰好包含K个输入的R和G(举行覆盖,二维前缀和+差分)。要使得“Colorfulness值尽可能小”,那么,此矩形最长边即为我们二分的对象。
扩展到RGB,就是三维前缀和+差分(容斥)。
OK,可以写代码了。
错误点
对代码能力不足,二分答案(查找的就是答案)理解不足,高维前缀和不熟练。
正解
#include <bits/stdc++.h>
using namespace std;
const int N = 100005, M = 260;
int n, K;
int vis[M][M][M];
int sum[M][M][M];
int mx;
int calc(int x, int y, int z, int d){int res = sum[x][y][z];res -= (sum[x - d - 1][y][z] + sum[x][y - d - 1][z] + sum[x][y][z - d - 1]);res -= sum[x - d - 1][y - d - 1][z - d - 1];res += (sum[x - d - 1][y - d - 1][z] + sum[x][y - d - 1][z - d - 1] + sum[x - d - 1][y][z - d - 1]);return res;
}
bool check(int x){for (int i = x + 1; i <= mx; i++){for (int j = x + 1; j <= mx; j++){for (int k = x + 1; k <= mx; k++){if (calc(i, j, k, x) >= K){return true;}}}}return false;
}
int main(){freopen("rgb.in", "r", stdin);freopen("rgb.out", "w", stdout);cin >> n >> K;for (int i = 1; i <= n; i++){int r, g, b;cin >> r >> g >> b;r++; //防越界g++; //防越界b++; //防越界sum[r][g][b]++;mx = max({mx, r, g, b});}for (int i = 1; i <= mx; i++){for (int j = 1; j <= mx; j++){for (int k = 1; k <= mx; k++){sum[i][j][k] += sum[i][j][k - 1];		}}}for (int i = 1; i <= mx; i++){for (int j = 1; j <= mx; j++){for (int k = 1; k <= mx; k++){sum[i][j][k] += sum[i][j - 1][k];		}}}for (int i = 1; i <= mx; i++){for (int j = 1; j <= mx; j++){for (int k = 1; k <= mx; k++){sum[i][j][k] += sum[i - 1][j][k];		}}}int l = 1, r = mx;int ans;while (l <= r){int mid = (l + r) >> 1;if (check(mid)){ans = mid;r = mid - 1; }else{l = mid + 1;}}cout << ans;
} 
T3.rescue
提交链接:ZYZOJ P6000 rescue
原题链接:https://www.luogu.com.cn/problem/P6419
题面
A村泛洪水,小A要拯救村民。村庄分布形如一棵树,有n座房子通过n-1条边相连。小Z准备开卡车营救村庄,每条边有一个时间权值,有一个基地(小Z初始位于基地,每次救援不必返回基地,救援结束也不必)处于某一节点。给出需要救援的房子,可以任意选择救援顺序,输出每个节点作为基地的最短用时。
分析
换根dp的模板,但我没学,所以现在去学,粘一下std。
错误点
不会换根dp
std
#include<cstdio>
#include<algorithm>
using namespace std;
const int M=5e5+5;
void qread(int &r) {//IO数据很大啊,用读入挂可能会好一点r=0;char c=0;while(c<'0'||c>'9')c=getchar();while(c>='0'&&c<='9')r=(r<<1)+(r<<3)+(c^48),c=getchar();
}
int n,m;
struct edge {int v,c,to;
} E[M<<1];
int head[M],tot;
void Link(int u,int v,int c) {E[++tot]=(edge) {v,c,head[u]};head[u]=tot;
}
bool mark[M];
long long dis[M],len,sz[M];
long long from_f[M],from_s[M];
void dfs_Init(int u,int f) {//这一次dfs预处理很多东西if(mark[u])sz[u]=1,from_s[u]=0;else sz[u]=0,from_s[u]=-2e18;for(int i=head[u]; i!=0; i=E[i].to) {int v=E[i].v,c=E[i].c;if(v==f)continue;dis[v]=dis[u]+c;//深度dfs_Init(v,u);sz[u]+=sz[v];//子树内标记点数量if(sz[v]>0)len+=c*2;//len在根为1时的初始值from_s[u]=max(from_s[u],from_s[v]+c);//子树内深度}
}
void re_dfs_Init(int u,int f) {long long fir=-2e18,sec=-2e18;//最大值First,次大值Secondfor(int i=head[u]; i!=0; i=E[i].to) {int v=E[i].v,c=E[i].c;if(v==f)continue;long long Dis=from_s[v]+c;if(Dis>fir)sec=fir,fir=Dis;else if(Dis>sec)sec=Dis;}for(int i=head[u]; i!=0; i=E[i].to) {int v=E[i].v,c=E[i].c;if(v==f)continue;long long Dis=from_s[v]+c;if(Dis==fir)from_f[v]=max(from_f[u],sec)+c;//最大值以外的最大值是次大值else from_f[v]=max(from_f[u],fir)+c;if(mark[u])from_f[v]=max(from_f[v],(long long)c);//这里注意父亲被标记的情况(实测,比较难拍出来)re_dfs_Init(v,u);}
}
long long Ans[M];
void dfs_Solve(int u,int f,long long len) {Ans[u]=len-max(from_f[u],from_s[u]);for(int i=head[u]; i!=0; i=E[i].to) {int v=E[i].v,c=E[i].c;if(v==f)continue;long long nxt_len=len;if(sz[v]==0)nxt_len+=c*2;//这里是len的O(1)递推转移else if(sz[v]==m)nxt_len-=c*2;dfs_Solve(v,u,nxt_len);}
}
void Solve() {dfs_Init(1,-1);if(!mark[1])from_f[1]=-2e18;re_dfs_Init(1,-1);dfs_Solve(1,-1,len);for(int i=1; i<=n; i++)printf("%lld\n",Ans[i]);
}
int main() {freopen("rescue.in", "r", stdin);freopen("rescue.out", "w", stdout);scanf("%d%d",&n,&m);for(int i=1; i<n; i++) {int u,v,c;qread(u),qread(v),qread(c);Link(u,v,c);Link(v,u,c);}for(int i=1; i<=m; i++) {int u;qread(u);mark[u]=true;}Solve();return 0;
} 
T4.path
提交链接:ZYZOJ P6001 path
原题链接:https://www.luogu.com.cn/problem/P2934
分析
订出这题就更不可能了,但是最短树是值得一学的。现在就去!
错误点
纯不会。
整场总结
时间:2025-11-03 8:00~12:30
完成题目:0/4
预估的分:50/400
实际得分:0/400
心态:较焦虑
| 题号 | 知识点 | 难度预估 | 用时 | 结果 | 得分 | 
| A.piano | 映射,一元一次方程 | 橙 | 1.5h | 爆零 | 0 | 
| B.rgb | 高维前缀和,降维,维度转化 | 黄 | 0h | 爆零 | 0 | 
| C.rescue | 换根DP | 紫 | 0h | 爆零 | 0 | 
| D.path | 最短路树,LCA,并查集 | 蓝 | 0h | 爆零 | 0 | 
卡点分析:
A——映射及整除问题
B——不会多维转化以及二分答案check函数编写
C——不会换根DP
D——最短路不熟悉
收获
降维思想,去绝对值思想,映射思想。
薄弱
代码能力以及对于思路的细化。
改进
大模拟+随手记录思路
