hdu3434 Sequence Adjustment

首先把序列变成长度 n1 的差分数列,那么这时的目标是将这个序列的每一个值都变为 0 。将区间操作转化成差分数列上的操作,就有:
1.将任意一个数减去或加上1(此时只要直接对前缀区间或后缀区间操作即可)。
2.将任意两个数进行相反的加减操作(此时只要直接对这个区间进行操作即可)。
设这个数列中小于0的数的和为A,大于0的数的和为 B ,且A>B(其他的情况一样)。对于 B 这一部分,可以用B的次数直接两两消去,而且此时其他任何的操作都是多余的。而对于剩余的 AB ,最好的方法就是直接用 AB 的次数每次消去一个,因为此时其他任何的操作同样是多余的。即最少的次数为 B+AB=A
对于上面这个构造的过程,可以发现,在消去 B 对数之后,可以到达的数是固定的AB+1个,因为在同时消去两个数时,原数列中 a1 an 是不变的,并且当消去了 B 对数之后,原数列会变成一个单调数列(当然,也可以考虑先消去AB个数,那么最后剩余 2B 个数时会产生的数已经确定了,同样是 AB+1 个不同的数)。有个有趣的地方就是,可以发现最后数列一定处于 a1 an 之间,也就是说 AB+1=|a1an|+1
ps.把变换后的数列画成阶梯状的图推导就简单很多。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define clr(a) memset(a,0,sizeof(a))
typedef long long ll;
int n,ct=0;
ll ar[1000010];
void cl(){
    int i,j;ll a,b;
    scanf("%d",&n);
    for(i=1;i<=n;scanf("%I64d",&ar[i++]));
    for(i=2,a=b=0;i<=n;++i){
        if(ar[i]>ar[i-1])a+=ar[i]-ar[i-1];
        else
            b+=ar[i-1]-ar[i];
    }
    if(a<b)swap(a,b);
    printf("Case %d: %I64d %I64d\n",++ct,a,a-b+1);
};
int main(){
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
#endif
    int t;scanf("%d",&t);
    while(t--)cl();
    return 0;
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值