题意:
给定一个长度为 $n$ 的序列,现在这个序列可以不断地将第一个数放到最后,求过程中最小的逆序对。
思路:
一开始直接硬模拟了一发,结果是显然的。(自闭选手)
可以一开始直接求得原始序列的逆序数,然后考虑每一位往后移的过程中对答案的贡献, 然后取最小值即可。
当第一位的数字移动到最后一位的时候,那么比 $a[1]$ 小的数字的逆序就没有了,而增加了比 $a[1]$ 大的数字的逆序
即每一位数字对答案的贡献为 $n-a[i] - (a[i] - 1)$;
1 /* 2 * Author: windystreet 3 * Date : 2018-08-10 14:36:11 4 * Motto : Think twice, code once. 5 */ 6 #include<bits/stdc++.h> 7 8 using namespace std; 9 10 #define X first 11 #define Y second 12 #define eps 1e-5 13 #define gcd __gcd 14 #define pb push_back 15 #define PI acos(-1.0) 16 #define lowbit(x) (x)&(-x) 17 #define bug printf("!!!!! "); 18 #define mem(x,y) memset(x,y,sizeof(x)) 19 20 typedef long long LL; 21 typedef long double LD; 22 typedef pair<int,int> pii; 23 typedef unsigned long long uLL; 24 25 const int maxn = 5e3+7; 26 const int INF = 1<<30; 27 const int mod = 1e9+7; 28 29 int tree[maxn]; 30 int n; 31 void init(){ 32 for(int i=0;i<=n;i++) 33 tree[i]=0; 34 return; 35 } 36 void add(int x,int v){ 37 for(int i=x;i<=n;i+=lowbit(i)) 38 tree[i] += v; 39 return ; 40 } 41 int query(int x){ 42 int res = 0; 43 for(int i=x;i;i-=lowbit(i)) 44 res += tree[i]; 45 return res; 46 } 47 48 int s[maxn]; 49 50 void solve(){ 51 int ans ; 52 while(scanf("%d",&n)!=EOF){ 53 init(); 54 for(int i=1;i<=n;i++){ 55 scanf("%d",&s[i]); 56 ++s[i]; 57 } 58 int sum = 0; 59 for(int i=1;i<=n;i++){ // 计算原始序列的逆序数 60 add(s[i],1); 61 sum += i - query(s[i]); 62 } 63 ans = sum; 64 for(int i=1;i<=n;i++){ 65 sum += n - s[i] - (s[i] - 1); // 对于每一位的贡献更新答案 66 ans = min(ans,sum); // 取最优解 67 } 68 printf("%d ",ans); 69 70 } 71 return; 72 } 73 74 int main() 75 { 76 // freopen("in.txt","r",stdin); 77 // freopen("out.txt","w",stdout); 78 // ios::sync_with_stdio(false); 79 int t = 1; 80 //scanf("%d",&t); 81 while(t--){ 82 // printf("Case %d: ",cas++); 83 solve(); 84 } 85 return 0; 86 }