CUIT ACM Personal Training 11.27(FM)J - Building Permutation

J - Building Permutation

Time Limit:2000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u

Description

Permutation p is an ordered set of integers p1,  p2,  ...,  pn, consisting of n distinct positive integers, each of them doesn't exceed n. We'll denote the i-th element of permutation p as pi. We'll call number n the size or the length of permutation p1,  p2,  ...,  pn.

You have a sequence of integers a1, a2, ..., an. In one move, you are allowed to decrease or increase any number by one. Count the minimum number of moves, needed to build a permutation from this sequence.

Input

The first line contains integer n (1 ≤ n ≤ 3·105) — the size of the sought permutation. The second line contains n integers a1, a2, ..., an ( - 109 ≤ ai ≤ 109).

Output

Print a single number — the minimum number of moves.

Please, do not use the %lld specifier to read or write 64-bit integers in С++. It is preferred to use the cin, cout streams or the %I64dspecifier.

Sample Input

Input
       
       
2
3 0
Output
2
Input
       
       
3
-1 -1 2
Output
6

Hint

In the first sample you should decrease the first number by one and then increase the second number by one. The resulting permutation is (2, 1).

In the second sample you need 6 moves to build permutation (1, 3, 2).



题解:这个题也是简单的贪心,给你一串数字,让你每次加一或者减一,使得他们可以形成一个以1为公差的等差数列。样例是很有误导性的,主要原因是他并没有排好顺序。其实这个问题只要进行排序之后,依次变化成坐标就可以了。为什么这就是最优解呢?首先我们给出3 4 5,要使得他们变成1 2 3,那么对应变换,也就是5->3,4->2,3->1,可以达到步数最短,这个我们可以通过数学推导来证明,比如有有k>p>q,使得他们变成m,m+1,m+2,那么如果按照刚才的对应,我们变化的总次数是|k-m-2|+|p-m-1|+|q-m|。如果不按照那个顺序来,我们变化的次数可能就会变成|k-m|+|p-m-1|+|q-m-2|之类的,如果q>=m+2时,结果确实与刚才的对应变化次数相同。q<m+2时,前一次的结果是k+p+q-3m-3,后一次的结果是k+p-q+1-m,用后面的减前面的就会发现结果是2m+4-2q,因为q<m+2,所以最后结果是大于0的。所以同理去推导,当按照递增的顺序变成1,2,3的序列步数最少。


AC代码如下:

#include<bits/stdc++.h>
using namespace std;

long long sum = 0, a[300005];
int n,i,t;

int main()
{
    scanf("%d",&n);
    for(i=0;i<n;i++)
        scanf("%lld",&a[i]);
    sort(a,a+n);
    for(i=1;i<=n;i++)
        sum += abs(a[i-1] - i);
    printf("%lld\n",sum);
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值