Minimum Inversion Number HDU-1394(乱搞)

题意:

给定一个序列,可以把左边任意长度为$i$的连续序列移动到最右边(不改变连续序列的顺序)。如:

原序列为:$a_1,a_2,a_3,...,a_i,a_{i+1},...,a_{n-1},a_n$

移动后的序列为:$a_{i+1},a_{i+2},...,a_{n-1},a_n,a_1,a_2,...,a_i$

问如何移动,使得序列中的逆序对数量最少,输出这个数量。

思路:

用$sum[i][j]$表示在区间$(i,j)$中存在多少个数和$a_i$可以组成逆序对。

设初始序列的逆序对的数量为$cnt$,那么对于每个移动分界点$i$,移动后的逆序对的数量为:

$cnt= \sum_{j=1}^{i-1}{(n-i+1)-2*(sum[j][n]-sum[j][i-1])}$

对$cnt$取$min$即可

代码:

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 #define PI acos(-1)
 4 using namespace std;
 5 
 6 const int maxn = 5e3 + 5;
 7 const int maxx = 1e5;
 8 const int inf = 0x3f3f3f3f;
 9 const ll INF = 0x3f3f3f3f3f3f3f3fLL;
10 
11 int arr[maxn];
12 int sum[maxn][maxn];
13 
14 int main()
15 {
16     int n;
17     while (~scanf("%d", &n))
18     {
19         for (int i = 1; i <= n; ++i)
20         {
21             scanf("%d", &arr[i]);
22         }
23         int cnt = 0;
24         for (int i = 1; i <= n; ++i)
25         {
26             for (int j = i + 1; j <= n; ++j)
27             {
28                 if (arr[i] > arr[j]) sum[i][j] = sum[i][j - 1] + 1, cnt++;
29                 else sum[i][j] = sum[i][j - 1];
30             }
31         }
32         int ans = cnt;
33         for (int i = 2; i <= n; ++i)
34         {
35             int x = cnt;
36             for (int j = 1; j < i; ++j)
37             {
38                 x += ((n - i + 1) - 2 * (sum[j][n] - sum[j][i - 1]));
39             }
40             ans = min(ans, x);
41         }
42         printf("%d\n", ans);
43     }
44 }

 

猜你喜欢

转载自www.cnblogs.com/zhang-Kelly/p/12639788.html