题解 P6874 [COCI2013-2014#6] KOCKICE
题目传送门
更好的阅读体验
算法分析:二分
提供一种基于二分的算法。
注意一下坑点:
- 最低那一列就是正中间那一列。
- “最低的列左右两侧的砖头数量必须相同”指的不是与中间列相邻的两列,而是所有对应的列。
下面来分析一下如何二分。
这里二分不直接二分答案。如果直接二分答案,并没有把原问题变成更简单的子问题。而二分的核心在于将复杂的原问题转化为较简单的子问题。因此,我们二分中间列的高度。
单调性在哪里?由于相邻的砖头高度恰相差
关于时间复杂度,检查可行性为
下面给出代码:
#include<bits/stdc++.h>
#define ll long long
#define reg register
#define F(i,a,b) for(reg int i=a;i<=b;++i)
using namespace std;
inline ll read();
const int N=3e5+10;
int n,a[N],b[N];
ll ans,sum;
inline bool check(ll mid) {
int res=0;
F(i,1,n){
ll x=mid+abs(n/2+1-i);
res+=(a[i]>=x)+(b[i]>=x);//计算操作次数将-1的列数
}
return res>=n;
}
int main() {
n=read();
ll l=0,r=0;
F(i,1,n)a[i]=read(),r=max(r,(ll)a[i]);
F(i,1,n)b[i]=read(),r=max(r,(ll)b[i]);
while(l<=r){//二分
ll mid=l+r>>1ll;
check(mid)?l=mid+1,ans=mid:r=mid-1;
}
F(i,1,n){//统计答案
ll x=ans+abs(n/2+1-i);
sum+=abs(a[i]-x)+abs(b[i]-x);
}
printf("%lld",sum);
return 0;
}
inline ll read() {
reg ll x=0;
reg char c=getchar();
while(!isdigit(c))c=getchar();
while(isdigit(c))x=(x<<1ll)+(x<<3ll)+(c^48),c=getchar();
return x;
}
AC
欢迎交流讨论,请点个赞哦~