HDU-P5248:序列变换[二分答案]

HDU-P5248:序列变换[二分答案]

题目

题目在这里

Problem Description

给定序列A={A1,A2,…,An}, 要求改变序列A中的某些元素,形成一个严格单调的序列B(严格单调的定义为:Bi<Bi+1,1≤i<N)。

我们定义从序列A到序列B变换的代价为cost(A,B)=max(|Ai−Bi|)(1≤i≤N)。

请求出满足条件的最小代价。

注意,每个元素在变换前后都是整数。

Input

第一行为测试的组数T(1≤T≤10).

对于每一组:
第一行为序列A的长度N(1≤N≤105),第二行包含N个数,A1,A2,…,An.
序列A中的每个元素的值是正整数且不超过106。

Output

对于每一个测试样例,输出两行:

第一行输出:“Case #i:”。i代表第 i 组测试数据。

第二行输出一个正整数,代表满足条件的最小代价。

Sample Input

2
2
1 10
3
2 5 4

Sample Output

Case #1:
0
Case #2:
1

思路

题目也是看了很久才明白意思,开始还以为是一个排序的问题,结果WA了几发,万般无奈之下上网查了查题解,看到二分时的我恍然大悟。
在这个题目里主要要想明白的是不是根据序列求出答案,而是拿着可能的答案去试是否满足题意,二分法显然能胜任这样的工作。

代码

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
const int MAXN = 100005;

using namespace std;

int ans, a[MAXN], b[MAXN], len;
int cnt = 0;
bool judge(int x) {
    memcpy(b, a, sizeof(a)); //注意不能破坏原序列,故操作在新序列中进行
    b[0]-=x; //前面的元素值越小,越有利
    for(int i = 1; i < len; ++i) { //将b[i]构造成一个尽可能小的数字
        if(b[i]<=b[i-1]) {
            if(b[i]+x>b[i-1]) b[i] = b[i-1]+1;
            else return false;
        }
        else if(b[i]-x>b[i-1]) b[i] = b[i]-x;
        else b[i] = b[i-1]+1;
    }
    return true;
}
int main(void)
{
    int T, ans;
    scanf("%d", &T);
    while(T--) {
        scanf("%d", &len);
        for(int i = 0; i < len; ++i)
            scanf("%d", &a[i]);
        int L = 0, R = 1000005, mid; //L和R的值根据题目给出的范围得出
        while(L <= R) {
            mid = (L+R)/2;
            if(judge(mid)) {
                ans = mid;
                R = mid-1;
            }
            else
                L = mid+1;
        }
        printf("Case #%d:\n%d\n", ++cnt, ans);
    }
    return 0;
}
posted @   JACK121385  阅读(50)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示