题解:P16857 [GKS 2021 #F] Trash Bins
题解:P16857 [GKS 2021 #F] Trash Bins
题目传送门
一道适合入门新手的题,有一点点的思维需求(不会很多,大部分人应该都能看懂)。
算法标签
字符串、循环、数组。
题目大意
给定
具体思路
暴力
很容易发现,一个点的答案贡献一定是左右两边最近的垃圾桶(若存在)的距离的较小值,那么可以对于每一个点分别往左边和右边循环查找最近的垃圾桶,算出距离累加答案。但是这个时间复杂度不够优秀,在极端数据下处理单次数据的时间复杂度可能高达
正解
照着暴力的思路,我们发现时间过大的主要原因是每次都要枚举左边/右边的位置来找到垃圾桶,很多没有垃圾桶的位置会重复枚举,所以我们可以尝试将所有点的左边/右边最近的垃圾桶一起计算处理。先考虑左边,我们可以使用一个
正解复杂度分析
时间复杂度
我们需要先正序枚举维护
空间复杂度
处理过程中我们需要维护一个
总体来说,这个解法时间和空间性能都较好,常数也较小,十分优秀。
具体实现
实现细节
首先,long long。因为 int所能表示的范围(约 long long。
其次,为了方便我们大部分人从
再次,我们每个点的右边最近的垃圾桶距离可以不用数组存储,因为我们可以在边计算的时候边统计答案,既优化了空间又提升了时间性能(可以少一次循环)。
最后,要根据题目中的格式输出,不要只输出一个
参考代码
::::success[AC code]
这段代码是我在写下这篇题解时的最优解(即
AC 记录
马蜂微丑,请见谅。
#include<bits/stdc++.h>
using namespace std;
const int MAXN=5e5+10;
int res[MAXN];
int t;
int main(){
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);//关闭同步流。
cin>>t;
for(int Case=1;Case<=t;Case++){//循环处理每一组数据。
int n;
string s;
cin>>n>>s;
s=" "+s;//对齐下标。
int last=0;
for(int i=1;i<=n;i++){//正序处理左边最近的垃圾桶距离。
if(s[i]=='1'){//如果该位置有垃圾桶。
res[i]=0;
last=i;//更新最近垃圾桶位置。
}else{
if(last==0){
res[i]=0x3f3f3f3f;
}else{
res[i]=i-last;
}
}
}
last=n+1;//也可以换成 0,但是第 35 行的 n+1 也要随之更改。
long long ans=0LL;//注意开 long long。
for(int i=n;i>=1;i--){//逆序处理右边最近的垃圾桶距离。
if(s[i]=='1'){//如果该位置有垃圾桶。
last=i;//更新最近垃圾桶位置。
}else{
if(last==n+1){
ans+=res[i];
}else{
ans+=min(res[i],last-i);//取小并加入最终答案。
}
}
}
cout<<"Case #"<<Case<<": "<<ans<<endl;//输出答案,注意格式。
}
return 0;//好习惯。
}
:::: 完结撒花!