20260716模拟题解
总结
难度:CSP-S
得分:210(100+100+0+10)
题解
排队取餐
给出一个长度为 \(n\),按资历从高到低排序的成员队列,包含成员的到达时间和吃饭用时。一个成员吃完饭之后下一个成员再能开始吃,否则下一名成员需要等待。当多名成员都在等待,资历最高者去吃饭。
因为资历从高到低给出,所以就用输入的顺序作为资历。因为要不停维护资历最高的人吃法,所以使用优先队列。
同时,成员的到达时间能到达 \(10^9\),所以按时间遍历会超时。选择用最多到\(10^5\)的成员来遍历(这就意味着要按照到达时间进行一次排序),如果优先队列中没人,则跳过这一段时间,直接到下一位成员入队。
因为很简单且100pts了,所以不粘代码了。
连块消除
给出一个 \(n\) 行 \(10\) 列的矩阵,每次操作时面积大于 \(k\) 的连通块会被全部删除,操作完成后整个矩阵在重力的作用下下落。
找连通块就是朴素的dfs,因为有重力下落的挺像所以可以从下往上搜。重力的影响,每一列和每一列都是独立的,所以只用按列往下落就行了。
因为很简单且100pts了,所以就不粘代码了。
美味绕路
给出一个图,一部分节点上有干草堆,经过时可获得美味值。终点是 \(n\) 号节点,求对于从 \(1\) 到 \(n-1\) 的每一个起点,能否在吃一个干草堆的情况下,路程长度比最短路所增加的值,不超过干草堆的美味值(也就是绕路的路程 ≤ 干草堆的美味值)
连续不知道多少天简单图论不会做的开始,究其原因是我不会写 dijkstra 和 SPFA 了。
一气之下,把 dijkstra 模板默在这里。
dijkstra模板
struct node{
int to,edge;
};
int n,m,s;
vector<node> a[100010];
int d[100010],vis[100010];
priority_queue<pair<int,int> > q;//注意用法
void dijkstra(){
memset(d,0x3f,sizeof(d));
d[s]=0;
q.push(make_pair(0,s));//注意用法
while(q.size()){
int x=q.top().second;
q.pop();
if(vis[x]==1) continue;
vis[x]=1;
for(int i=0;i<a[x].size();i++){
if(d[x]+a[x][i].edge<d[a[x][i].to]){
d[a[x][i].to]=d[x]+a[x][i].edge;
q.push(make_pair(-d[a[x][i].to],a[x][i].to));
}
}
}
}
首先知道重点是不变的都是 \(n\) 号节点,所以可以先跑一边以\(n\) 号节点为起点的单源最短路(dijkstra),算出数组dist0。
容易从题面得到,如果要从点 s 开始,在点 h 多吃一个干草堆,路线的代价可以变成
从 s 到 h 的最短路 +dist0[h](h 到 n 的最短路) - 干草堆美味值
建立一个虚拟的点 S,把每一个有干草堆的点都和点S都连一条边,边权为dist0[h] - y(干草堆美味值)。
接着,以 S为起点再跑一边dijkstra,得到数组dist1。
得到的dist[x],就是从 x 节点出发,选择一个干草堆,再到 N 节点,最后减去干草堆美味值得到的“折算最短路”。最后只需要判断是否有dist1[x]≤dist0[x],有则输出 1,无则输出 0。
浙公网安备 33010602011771号