HDU - 5248

本文参考:
/* 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中的每个元素的值是正整数且不超过10^6。
 
/* Sample Input
2

2
1 10

3
2 5 4
 

Sample Output
Case #1:
0

Case #2:
1 */

# include <stdio.h>
# include <stdlib.h> 
int a[10000], n;

int judge(int num)/* 判断二分取得中间值num(调节Ai的允许变化量范围最大限度)是否能满足题意,假定这个num传入的就是所求的最小代价,,若返回1,则对num减半再检验 */
{
    int x = a[0] - num;/* 
    //定义x的时候同时给x初始化个值(表达式)为:a[0] - num(将原序列Ai的值削减掉num,既然假定这个num传入的就是所求的最小代价,那么第一个x<=序列B的最小值
    并且,对A序列每一个Ai都减去num并不会使得代价cost比 只对某单个Ai元素减去num时的cost变大),另外这时的x允许出现负数 */
    int y  = 0;
    for(int i=1; i<n; ++i)/* 以a[0]为基准(作为B序列中的最小值.) */
    {
        y = a[i] - num;/* (限制条件)分开写(先后遍历),多个标准同时考虑会使思维混乱 */
        if(y <= x)
        {
            y = x + 1;/* (根据递增要求)来更新y的值(放大y使得它与x相比有最小限度的增大量1(紧),使得满足递增条件同时|Ai−Bi|也最小,要与当前num比较 */
            if(abs(y - a[i]) > num)//(根据是否满足不超过num) 来检验当前这个num是否够大;y的变化未必连续
                return 0;//改变量超过这个num,不符合题意.
        }
        x = y;/* 迭代,刷新x,来比较下一个相邻y */
    }
    return 1;
}


int main()
{
    int t, cas = 1;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        
        for(int i=0; i<n; ++i)
            scanf("%d",&a[i]);
//二分取出一系列的mid,传入judge(),直到找到最小的那个cost(即num)
        int l=0, r=1000000, mid;//left和right边界
        while(l<r)
        {
            mid = (l+r)/2;
            if(judge(mid))
                r = mid;//刷新有边界
            else
                l = mid + 1;//刷新左边界
        }
        printf("Case #%d:\n%d\n",cas++, r);
    }
    return 0;
}
/* 
改变:比如对调/就地调整大小(当然,前者是后者的特殊情况),此处只考虑调整大小即可
进行二分处理,逐个判断可能的答案:
 编写函数 judge(int num) 来判断当最大代价为num(意思是current)时该序列   是否可以变成严格单调。
1.因为输入的每个数都在10^6内,所以答案也在10 ^6内,从10 ^6开始二分。

    对每个测试数进行测试.必要时削减去num大小来调整成单调(即便
    是对每一个数进行削减,cost也不会超过num,当然减掉num后可能出现负值,这不碍事)
   验证时要尽可能让第1个数变得最小,并且让数紧凑。
2.二分枚举最大改变量/分摊改变量 
对于改变量mid,a[0]=a[0]-mid(先尽可能把第一个数变小),然后从第二个数向后判断,
先让a[i]=a[i]-mid,如果b[i]<=b[i-1],说明b【i】此时减的过多了,b[i]=b[i-1]+1(让序列尽可能的紧凑),
然后判断abs(a[i]-b[i]),如果>mid, 说明mid过小,返回0,取右区间(较大区间)二分答案;
如果for循环结束返回1,说明mid>=最优解,取左区间(较小区间)二分答案。
   */

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值