原题链接:http://codeforces.com/problemset/problem/819/B
题意:把一个数列整体往右移k位(大于n位置的数移动到数列前端,循环滚动),定义该数列的“偏差值”:,
求在移动最少k位时,得到的最小“偏差值”。
思路:对于每个数每次往右移,其与i的差值-1,差值记为d,那么记录d>0和d<=0的位置个数;同时记录每个大于0的d的个数,保存在po数组内。
每次往右移,sum加上d<=0的个数,减去d>0的个数,对于将要移动到数列首位置的数,更新差值,进行特判,并更新po数组。
AC代码:
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cmath> 5 using namespace std; 6 const int MAXN = 2e6 + 10; 7 int a[MAXN], cnt_ne = 0, cnt_po = 0, d[MAXN]; 8 int ne[MAXN], po[MAXN]; 9 long long sum = 0; 10 int main() 11 { 12 int n; 13 scanf("%d", &n); 14 memset(ne, 0, sizeof(ne)); 15 memset(po, 0, sizeof(po)); 16 for (int i = 0;i<n;i++) { 17 scanf("%d", &a[i]); 18 d[i] = a[i] - i-1; 19 if (d[i]>0) { 20 cnt_po++; 21 po[d[i]]++; 22 } 23 else { 24 cnt_ne++; 25 ne[-d[i]]++; 26 } 27 sum += abs(d[i]); 28 } 29 int u = 0; 30 long long res = sum; 31 for (int i = 1;i<n;i++) { 32 //cout << sum << endl; 33 sum += cnt_ne; 34 sum -= cnt_po; 35 cnt_po -= po[i]; 36 cnt_ne += po[i]; 37 38 d[n - i] -= i - 1;//最后一个数更新差值 39 //再放到第一位,进行判断 40 if (d[n - i] <= 0) { 41 if (d[n - i] + n - 1>0) { 42 int dd = d[n - i] + n - 1 - (abs(d[n - i])+1); 43 d[n - i] += n - 1; 44 sum += dd; 45 46 cnt_po++; 47 cnt_ne--; 48 po[d[n - i] + i]++; 49 } 50 else sum -= n; 51 }else sum += n - 2; 52 53 if (res>sum) { 54 res = sum; 55 u = i; 56 } 57 } 58 cout << res << ' ' << u << endl; 59 }