Codeforces285C Building Permutation

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 integersa1, 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).

 

题意:给出N个数字,要求这些数字全都符合1 <= ai <=n,比如-1到1需要两步,变0再变1。求最小步数。

这种题目其实都是一种解决方法,贪心就好了,能到哪个就到哪个,比如第二个样例,完全可以变为1 2 3的,这样的步数也依然是6,所以他给的提示很有误导性的说。所以我一开始决定开一个VST数组,然后让这个数字向上向下走去找他最靠近哪个还未标记的数字,就让这个数字变为这个数字记录步数就好了。这样确实是一种贪心。

然并卵,超时了。。。数据量是3*10^5,如果有1000个最后面的数字要一直找到1000以内才找到未标记的点,那么这个运算量是已经是3*10^8这样,妥妥的炸了。

除了贪心还有其他解法?答案是,木有- -。然后发现既然你要贪心,而且都要变成[1,n]以内的数字,你就直接让当前的数字变成下标的大小,然后加起来不就好了吗?这也是贪心啊,你让他直接变成下标的大小,但是这个贪心有问题,连样例都过不了的。那么,如果先把他排序呢?这样得到的步数就肯定是最小的了。这样就相当于把vst直接换成了下标,倒转过来想问题,复杂度一下子就下去了,很神奇啊!

得出解法就是,先排序再遍历一次求sum。

代码如下:

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
long long sum = 0, a[300005];
int main()
{
	int n,i,t;
	scanf("%d",&n);
	for(i=0;i<n;i++)
		scanf("%I64d",&a[i]);
	sort(a,a+n);
	for(i=1;i<=n;i++)
		sum += abs(a[i-1] - i);
	printf("%I64d\n",sum);
	return 0;
}


 

用long long的原因是,因为比如3*10^5全部都是-10^9,那么加到1就已经至少要3*10^5*10^9这个sum了,所以肯定要上long long的。

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值