AT_abc443_C~E题题解

problem C \Large problem\ C problem C

不算太复杂。

每次记录上一次关机的时间 lastlastlast,当青木在 aia_iai 来过时,如果 last+100<ailast+100<a_ilast+100<ai,则答案加上 ai−(last+100)a_i-(last+100)ai−(last+100),否则不做任何处理。

当 n=0n=0n=0 时记得特判。

cpp 复制代码
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long

using namespace std;

int a[300005];
int main(){
	int n,t;
	cin>>n>>t;
	for(int i=1;i<=n;i++)cin>>a[i];
	if(n==0){//一次都没有来过,特判 
		cout<<t;
		return 0;
	}
	int ans=a[1];
	int las=a[1];//记录上次关机时间 
	a[n+1]=t;
	for(int i=2;i<=n+1;i++){
		if(las+100<a[i]){
			ans+=a[i]-las-100;
			las=a[i];
		}
	}
	cout<<ans;
	return 0;
}

problem D \Large problem\ D problem D

赛时没过QWQ。

题意:给一个矩阵,每一列都有一颗棋子,每次可以挑一个棋子向上移动一格,要求所有相邻的棋子行编号差的绝对值不超过 111,求最小操作次数。

每个棋子都对左右两边相邻的棋子有约束,如果一个棋子 iii 可能的高度是 fif_ifi,那么它左边的棋子 i−1i-1i−1 的最低可能的高度就是 min⁡(fi−1,fi+1)\min(f_{i-1},f_i+1)min(fi−1,fi+1),同样的,它右边的棋子 i+1i+1i+1 的最低可能的高度就是 min⁡(fi+1,fi+1)\min(f_{i+1},f_i+1)min(fi+1,fi+1)。

因此我们正着循环一遍,每次令 fi=min⁡(fi,fi−1+1)f_i=\min(f_i,f_{i-1}+1)fi=min(fi,fi−1+1),再倒过来循环,每次使 fi=min⁡(fi,fi+1+1)f_i=\min(f_i,f_{i+1}+1)fi=min(fi,fi+1+1),最后得到的 fff 就是能使答案最小且满足条件的解,它与原数组的差之和就是要操作的次数。

代码:

cpp 复制代码
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long

using namespace std;

ll a[300005];
ll b[300005];
void solve(){
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
		b[i]=a[i];
	}
	ll ans=0;
	for(int i=2;i<=n;i++)b[i]=min(b[i-1]+1,b[i]);
	for(int i=n-1;i>=1;i--)b[i]=min(b[i+1]+1,b[i]);
	for(int i=1;i<=n;i++)ans+=a[i]-b[i];//差之和就是答案
	cout<<ans<<endl;
}
int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		solve();
	} 
	return 0;
}

problem E \Large problem\ E problem E

光顾着想 D 了,E都没看。

借鉴了一位大佬的思路,orz。

题意:你站在一个地图的指定点处,每次可以向左上,正上或右上方移动一格,如果这个格子是墙,且这一列这个格子下方没有墙,就可以将这个墙清除,问对于第一行每一个点是否能到达。

观察清除墙的规则,可以发现,如果到达一列最下方的或以下,一直往上走,那么这一列所有的墙都可以被清空,换句话说,第 jjj 列最后一个障碍在第 kkk 行,且当前到达了 (i,j)(i,j)(i,j) 且 i≥ki\ge ki≥k,那么第 jjj 列的所有障碍都可以被无视,相当于第 jjj 列被打通了。

记录每一列的打通情况,广搜可以解决。

cpp 复制代码
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long

using namespace std;

char a[3005][3005];
bool vis[3005][3005];
//记录是否到达过 
int ope[3005],las[3005];
// ope记录打通情况,las表示每一列的最后一个障碍 
int dx[4]={-1,-1,-1};
int dy[4]={-1,0,1};//增量数组减少码量 
void solve(){
	int n,c;
	scanf("%d%d",&n,&c);
	for(int i=1;i<=n;i++)scanf("%s",a[i]+1);
	for(int i=1;i<=n;i++){
		ope[i]=las[i]=0;
		for(int j=1;j<=n;j++)vis[i][j]=0;
	}//多组数据记得清空 
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			if(a[i][j]=='#')
				las[j]=max(las[j],i);
	queue<pair<int,int> > q;
	q.push({n,c});
	vis[n][c]=1;
	ope[c]=1;
	while(q.size()){
		int x=q.front().first;
		int y=q.front().second;
		q.pop();
		for(int i=0;i<3;i++){
			int xx=x+dx[i],yy=y+dy[i];
			if(xx<1||xx>n||yy<1||yy>n||vis[xx][yy])continue;
			if(a[xx][yy]=='#'&&!ope[yy]&&xx<las[yy])continue;
			if(xx>=las[yy])ope[yy]=1;
			vis[xx][yy]=1;
			q.push({xx,yy});
		} 
	}
	for(int i=1;i<=n;i++)cout<<vis[1][i];
	cout<<endl;
	return;
}
int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		solve();
	} 
	return 0;
}
相关推荐
_清歌3 小时前
DSpark 深度解读:DeepSeek-V4 如何用「半自回归」把推理速度提升 85%
算法
统计实现局3 小时前
SVD 的三步走:双对角化、Givens 收敛、排序
算法
躬行见万象3 小时前
《VLA 系列》UniLab 强化训练 | G1 机器人 |复现
算法
统计实现局3 小时前
对称不定分解(Bunch-Kaufman):为什么 Cholesky 不够用
算法
统计实现局3 小时前
dqrsl 拆解:拿着 QR 结果能算出哪 5 种东西
算法
统计实现局3 小时前
为什么 Cholesky 求逆比 Gauss-Jordan 快一倍——行列式溢出防护详
算法
To_OC15 小时前
LC 994 腐烂的橘子:人人都说是 BFS 入门题,我却写了三遍才过
javascript·算法·leetcode
金銀銅鐵18 小时前
[Python] 扩展欧几里得算法
python·数学·算法
To_OC21 小时前
LC 200 岛屿数量:经典 DFS 入门题,我第一次写居然连方向都搞错了
javascript·算法·leetcode