链接:
http://codeforces.com/contest/819/problem/B
题意:
有n个数,从1到n乱序排列,定义这n个数的秩序值为∑(a[i]-i) (1<=i<=n), 你每次将这个数组向右循环移位p次,
问p等于多少时,这n个数的秩序值最小?
题解:
记录下每个数是在目标位置的左边还是右边,存下所有在目标左边的数,
cur[i]表示初始数组中有多少个数在它目标左边第i个位置上
->注意要存下一开始在目标左边(包括在目标上)的个数L,以及目标右边的数的个数r
之后直接模拟右移,对于第i次右移,L = L-cur[i-1], r = r+cur[i-1],即当次位移刚好有cur[i-1]个数原本在目标位置左
边及目标上跑到了目标位置的右边,
每次的秩序值便是初始秩序值-L+r+特判最后一个数移到第一个数所产生的影响
但注意计算之后L还要+1,r还要-1因为最后一个数跑到了第一个
代码:
31 int n; 32 int p[MAXN]; 33 int cur[MAXN * 2]; 34 35 int main() { 36 ios::sync_with_stdio(false), cin.tie(0); 37 cin >> n; 38 int L = 0, R = 0; 39 ll sum = 0; 40 rep(i, 1, n + 1) { 41 cin >> p[i]; 42 sum += abs(p[i] - i); 43 if (p[i] >= i) L++, cur[p[i] - i]++; 44 else R++; 45 } 46 ll ans = sum; 47 int pos = 0; 48 rep(i, 0, n - 1) { 49 L -= cur[i]; 50 R += cur[i]; 51 sum = sum - L + R - abs(p[n - i] - n - 1) + p[n - i] - 1; 52 cur[p[n - i] + i]++; 53 L++, R--; 54 if (sum < ans) ans = sum, pos = i + 1; 55 } 56 cout << ans << ' ' << pos << endl; 57 return 0; 58 }