The 2021 ICPC Asia Jinan Regional Contest - Problem D - 2021 icpc 亚洲区域赛济南站D题 (三分答案)

题目大意:给你一个数组,让你把这个数组变成一个等差数列,问最小的操作次数是多少。

操作一次是指使一个数加1或者减1。

思路:刚看到这道题的时候,很容易想到用直线去拟合数组,但是如果去枚举可能的斜率看到会超时,因为斜率的取值范围为-1e13到1e13,如果用枚举两点直接连线的斜率很显然也是会超时的(O($$n^2))。如果我们令f(x)为当斜率为x时的最小操作次数,不难发现f(x)是一个凹凸性不变的函数,因此可以使用三分来枚举斜率。

如何判断这个斜率下的最少操作次数?不难发现,当数组表示的点均匀分布在直线两侧时,操作总次数最少。所以我们假设使用第一个元素作为直线上的点,枚举所有元素到直线的垂直距离,把结果存在a数组里面,所有垂直距离的和就是这个直线在取当前截距的操作次数。因此,我们只需要找到a数组的中位数作为基准点进行求解即可。

注意:由于三分的时间复杂度要高于二分,因此求中位数禁止使用sort(实测在PTA平台提交会TLE),请使用快速选择算法或者部分快速排序,下面的代码使用了北京大学提供的题解上使用的nth_element函数求解。还有由于数据范围过大(1e13*2e5),在运算过程中可能会爆long long,请使用128位整数__int128,或者手写高精度,不过应该没人这么干

#include<bits/stdc++.h>

#define int long long

using namespace std;

const int N=2e6+5;
const int mod=998244353;

ostream& operator<<(ostream& os, __int128 t) {
    if (t==0) return os << "0";
    if (t<0) {
        os<<"-";
        t=-t;
    }
    int a[50],ai=0;
    memset(a,0,sizeof a);
    while (t!=0){
        a[ai++]=t%10;
        t/=10;
    }
    for (int i=1;i<=ai;i++) os<<abs(a[ai-i]);
    return os<<"";
}

int n;
__int128 a[N];
long long c[N];

__int128 check(__int128 num){
	a[1]=0;
	int tb=c[1];
	for(int i=2;i<=n;i++){
		a[i]=c[i]-tb-num*(i-1);
	}
	nth_element(a+1,a+(n+1)/2,a+n+1);
	__int128 temp=a[((n+1)>>1)];
	__int128 res=0;
	for(int i=1;i<=n;i++){
		if(temp-a[i]>0)res+=temp-a[i];
		else res-=temp-a[i];
	}
	return res;
}
void io() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
}
signed main(){
    io();
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>c[i];
	}
	__int128 l=-1e13;
	__int128 r=1e13;
	while(l<r){
		__int128 midl=l+(r-l)/3;
		__int128 midr=r-(r-l)/3;
		if(check(midl)>check(midr)){
			l=midl+1;
		}else{
			r=midr-1;
		}
	}
	cout<<check(l)<<endl;
	return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值