题意描述:
这个题目提问的是,在插入排序的序列给定的情况下,求最少需要移动的次数。
序列的长度n <=10^5
序列中的元素a[i] <=10^6
一组数据中case数t <=5
题目分析:
这个题,拿到题目一眼望去满满的都是暴力的影子(又傻逼了)。
然后仔细分析一下暴力的复杂度,每插入一个元素都要扫过一边数组,显而易见的O(n*n),TLE思密达。
然后再认真分析一下题目,所求最少的移动次数,也就是说:对于其中任意一个元素a[i],只需要求出从a[1]到a[i-1]中大于a[i]的数字的数量。
说白了就是逆序数。。。
之后就是寻找一种数据结构或者算法可以在o(n)更短的时间内求出逆序数
动手:
线段树和树状数组十分适合这题,于是研习一下百度搜到的神牛的代码,迅速山寨了一个线段树的代码。
1 #include <cmath> 2 #include <cstdio> 3 #include <vector> 4 #include <iostream> 5 #include <algorithm> 6 #include <cstring> 7 using namespace std; 8 9 const int MAXN = 1000000+5; 10 11 struct Node{ 12 int a,b,left,right,val; 13 }; 14 15 Node tree[MAXN*2]; 16 int L = 0; 17 int a[100000+5]; 18 19 void B( int x, int y ){ 20 //cout<<x<<" "<<y<<endl; 21 int This = L; 22 tree[This].a = x; 23 tree[This].b = y; 24 tree[This].val = 0; 25 if ( y - x >= 1 ){ 26 int mid = (x+y)/2; 27 L++; 28 tree[This].left = L; 29 B(x,mid); 30 L++; 31 tree[This].right = L; 32 B(mid+1,y); 33 } 34 //cout<<"DONE "<<x<<" "<<y<<endl; 35 } 36 37 void I( int x, int y, int t ){ 38 //cout<<"I "<<x<<" "<<y<<" "<<t<<endl; 39 if ( ( x <= tree[t].a ) && ( y >= tree[t].b ) ){ 40 tree[t].val++; 41 }else{ 42 tree[t].val++; 43 int mid = (tree[t].a+tree[t].b)/2; 44 if ( x <= mid ){ 45 I(x,y,tree[t].left); 46 } 47 if ( y >= mid+1 ){ 48 I(x,y,tree[t].right); 49 } 50 } 51 } 52 53 int S( int x, int y, int t ){ 54 if ( tree[t].val == 0 ){ 55 return 0; 56 } 57 if ( ( x<= tree[t].a ) && ( y >= tree[t].b ) ){ 58 return tree[t].val; 59 }else{ 60 int mid = (tree[t].a+tree[t].b)/2; 61 int ans = 0; 62 if ( x <= mid ){ 63 ans += S(x,y,tree[t].left); 64 } 65 if ( y >= mid+1 ){ 66 ans += S(x,y,tree[t].right); 67 } 68 return ans; 69 } 70 } 71 72 int G( int x, int y ){ 73 return S(0,y,0)-S(0,x,0); 74 } 75 76 void show(int k){ 77 for ( int i = 0; i<= k; i++ ){ 78 cout<<i<<" f "<<tree[i].a<<" t "<<tree[i].b<<" "<<tree[i].left<<" "<<tree[i].right<<" "<<tree[i].val<<endl; 79 } 80 } 81 82 void solve(){ 83 int n; 84 cin>>n; 85 int i = 0; 86 int MAX = 0; 87 long long ans = 0; 88 int MIN = 1000000+10; 89 memset(a,0,sizeof(a)); 90 for ( i = 0; i < n; i++ ){ 91 cin>>a[i]; 92 if ( MAX < a[i] ){ 93 MAX = a[i]; 94 } 95 if ( MIN > a[i] ){ 96 MIN = a[i]; 97 } 98 } 99 //cout<<MAX<<endl; 100 //cout<<MIN<<endl; 101 B(MIN-1,MAX); 102 //show(L); 103 //cout<<"sb"<<endl; 104 for ( i = 0; i < n; i++ ){ 105 I(a[i],a[i],0); 106 ans += G(a[i],MAX); 107 } 108 cout<<ans<<endl; 109 } 110 111 112 int main() { 113 int t; 114 int i; 115 cin>>t; 116 for ( i = 0; i <t; i++ ){ 117 L = 0; 118 solve(); 119 } 120 return 0; 121 }
想起来个要命的事儿就是用python3写会超时,可能是python内部开内存的方式比较慢,不像C++写在外面,是直接开出来的。
这题后来拿给狗哥做了一发,结果用了个树状数组就给我平了,,,虽然差不大多,但是代码量要小很多,看来需要研习一下了。