二分法在解空间搜索:Sequence transformation

这是一个关于算法的问题,目标是计算将给定序列转换为严格单调递增序列所需的最小成本。通过分析序列的边界条件,确定成本的范围,并使用二分搜索找到最小成本。在判断函数中,采用贪心策略检查每个元素,确保它们在增加成本后仍能形成递增序列。代码中展示了如何实现这个算法。

题目描述

Given sequence A={A1,A2,…,An}, it is required to change some elements in sequence A to form a strictly monotonic sequence B (strictly monotonic is defined as: Bi<Bi+1,1≤i <N).
We define the cost of the transformation from sequence A to sequence B as cost(A,B)=max(∣Ai−Bi∣)(1≤i≤N)cost(A,B)=max(|A_i−B_i|)(1≤i≤N)cost(A,B)=max(AiBi)(1iN). Please calculate the minimum cost for the transformation.
Note that each element is an integer before and after the transformation.

输入

The input contains multiple test cases. Each test case contains an integer N (0<N<1050<N<10^50<N<105), the length of the sequence. The next line are N integers a1, a2, … , an (0<ai<106,1<=i<=N0<ai<10^6, 1<=i<=N0<ai<106,1<=i<=N). The input terminates at the end of file (EOF).

输出

For each test case, print the minimum cost.

样例输入

5
1 4 4 4 3

样例输出

2

思路

  首先确定解的范围,下界为0,当原序列为严格递增时取0。考虑上界,本题的耗费定义为 cost(A,B)=max(∣Ai−Bi∣)(1≤i≤N)cost(A,B)=max(|A_i−B_i|)(1≤i≤N)cost(A,B)=max(AiBi)(1iN),所以我们只要考虑A序列和B序列相差最大的元素。当序列A无重复元素时,可以得出B1≥min{Ai∣0≤i≤n}且Bn≤max{Ai∣0≤i≤n}B_1 \geq min\{ A_i | 0\leq i \leq n \} 且 B_n \leq max\{ A_i|0\leq i \leq n \}B1min{Ai0in}Bnmax{Ai0in}这是因为,我们直接将A序列排序即可得到一个B序列,但此时不一定能使cost最小。再考虑有重复的情况,由于采用二分法cost范围对时间复杂度影响不大,可得0≤cost≤max(A)−min(A)+n0 \leq cost \leq max(A)-min(A)+n0costmax(A)min(A)+n 再在这个范围里利用二分法找到最小的满足条件(只要修改基本二分查找的判断逻辑即可)。
  判断函数输入一个cost值,检查在该条件下能否令A序列变成严格单调递增的序列。采用贪心策略,从0到n依次检查每一个元素,令每一个元素再保证大于其前一个元素的基础上尽量小,若Ai+cost≤Ai−1A_i+cost\leq A_{i-1}Ai+costAi1则返回False

代码

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
using namespace std;
int n;
long long a[100007];

bool judge(long long cost)
{
	long long pre = a[0] - cost;
	for (int i = 1; i < n; i++)
	{
		//令a[i]尽量小
		if (a[i] - cost > pre)
		{
			pre = a[i] - cost;
		}
		else
		{
			if (a[i] + cost <= pre)
			{
				return false;
			}
			pre++;
		}
	}
	return true;
}


int main()
{
	while (~scanf("%d", &n))
	{
		long long max = 0;
		long long min = 1000000;
		memset(a, 0, sizeof(a));
		for (int i = 0; i < n; i++)
		{
			scanf("%lld", &a[i]);
			if (a[i] > max) max = a[i];
			if (a[i] < min) min = a[i];
		}
		long long le = 0;
		long long ri = max - min + n;
		while (le <= ri)
		{
			long long mid = le + (ri - le) / 2;
			if (judge(mid))
			{
				ri = mid - 1;
			}
			else
			{
				le = mid + 1;
			}
		}
		printf("%lld\n", le);
	}
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值