HDU 1394 Minimum Inversion Number
2014-10-03 19:27
387 查看
题意:
意思就是给你一个序列,令第一次的序列为a1, a2, ...an-1, an.第二次序列为a2, a3, ...an, a1,然后第三次,直到第n次an, a1, .... an-1。
求这些序列里面,逆序数最小的数。
思路:
暴力的话肯定是不行了,5000的n^2算法铁定超时。
1.
由于每次都是移动第一个数,而且只有n个不重复的数。
那么我就可以推出这个数在第一位和最后一位的逆序数,移到最后是增加的。
同理, 我也可以推出这个数对其他的数的影响,移到最后是减去的。
一减一加, 就得到了第二次序列的,以此类推就可以得到后面的序列的逆序数了。
例如:
总共有6个数,序列为 4 3 1 0 2 5
把4移动到最后,逆序数增加 (5 - 4) 个,因为总共这个序列里面比它大的只有5,,而且最开始4的逆序数为0。
4对其它的数的影响是逆序数4 个, 因为这个序列里面 0 1 2 3 都比它小并且在它后面。
2.
原始序列的逆序数可以利用线段树或者归并排序使复杂度降到O(nlogn)。
线段树:
求每个数的逆序数,求的就是在这个数前面有几个比它大的数。
那么,我们就可以把每个数当成线段树的一个节点,是几就插到第几个里面,
如果值是1的话,证明有这个数,没有则为0。
每次统计这个数以后的数有几个。
这样就可以在logn内里面求出这个数的逆序数了,当让每次操作都是n,所以合起来是nlogn。
归并排序:
由于归并排序的相对位置位置不变,所以在归并的过程中,就能判断在前面比它大的数有多少个。
而且每个数影响都来自于前面,这样按先左后右的顺序算下来,不会有遗漏或者重复。
Code(线段树):
Code(归并排序):
意思就是给你一个序列,令第一次的序列为a1, a2, ...an-1, an.第二次序列为a2, a3, ...an, a1,然后第三次,直到第n次an, a1, .... an-1。
求这些序列里面,逆序数最小的数。
思路:
暴力的话肯定是不行了,5000的n^2算法铁定超时。
1.
由于每次都是移动第一个数,而且只有n个不重复的数。
那么我就可以推出这个数在第一位和最后一位的逆序数,移到最后是增加的。
同理, 我也可以推出这个数对其他的数的影响,移到最后是减去的。
一减一加, 就得到了第二次序列的,以此类推就可以得到后面的序列的逆序数了。
例如:
总共有6个数,序列为 4 3 1 0 2 5
把4移动到最后,逆序数增加 (5 - 4) 个,因为总共这个序列里面比它大的只有5,,而且最开始4的逆序数为0。
4对其它的数的影响是逆序数4 个, 因为这个序列里面 0 1 2 3 都比它小并且在它后面。
2.
原始序列的逆序数可以利用线段树或者归并排序使复杂度降到O(nlogn)。
线段树:
求每个数的逆序数,求的就是在这个数前面有几个比它大的数。
那么,我们就可以把每个数当成线段树的一个节点,是几就插到第几个里面,
如果值是1的话,证明有这个数,没有则为0。
每次统计这个数以后的数有几个。
这样就可以在logn内里面求出这个数的逆序数了,当让每次操作都是n,所以合起来是nlogn。
归并排序:
由于归并排序的相对位置位置不变,所以在归并的过程中,就能判断在前面比它大的数有多少个。
而且每个数影响都来自于前面,这样按先左后右的顺序算下来,不会有遗漏或者重复。
Code(线段树):
#include<cstdio> #include<cstdlib> #include<cmath> #include<cstring> #include<iostream> #include<algorithm> #include<string> #include<queue> #include<stack> #include<bitset> #include<set> #include<map> #include<cctype> #include<vector> #define TEST #define LL long long #define Mt(f, x) memset(f, x, sizeof(f)); #define xep(i, n) for(int i = 0; i < (n); ++i) #define rep(i, s, e) for(int i = (s); i <= (e); ++i) #define dep(i, s, e) for(int i = (s); i >= (e); --i) #ifdef TEST #define See(a) cout << #a << " = " << a << endl; #define See2(a, b) cout << #a << " = " << a << ' ' << #b << " = " << b << endl; #define debug(a, s, e){ rep(_i, s, e) {cout << a[_i] << ' '; }cout << endl;} #define debug2(a, s, e, ss, ee) rep(i_, s, e) {debug(a[i_], ss, ee);} #else #define See(a) {} #define See2(a, b) {} #define debug(a, s, e) {} #define debug2(a, s, e, ss, ee) {} #endif const int MAX = 2e9; const int MIN = -2e9; const int PI = acos(-1.0); const double eps = 1e-9; using namespace std; #define lson l, m, rt << 1 #define rson m + 1, r, rt << 1 | 1 const int N = 5000 + 5; int sum[N << 2]; int a ; inline void pushUp(int rt) { sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; } int query(int L, int R, int l, int r, int rt) { if(l >= L && r <= R) { return sum[rt]; } int m = (l + r) >> 1; int ret = 0; if(L <= m) ret += query(L, R, lson); if(R > m) ret += query(L, R, rson); return ret; } void update(int I, int l, int r, int rt) { if(l == r) { sum[rt] = 1; return ; } int m = (l + r) >> 1; if(I <= m) update(I, lson); else update(I, rson); pushUp(rt); } int main() { int n; while(~scanf("%d", &n)) { rep(i, 1, n) { scanf("%d", &a[i]); ++a[i]; } Mt(sum, 0); int tem = 0; rep(i, 1, n) { tem += query(a[i], n, 1, n, 1); update(a[i], 1, n, 1); } int ans = tem; rep(i, 1, n) { tem = tem + (n - a[i]) - (a[i] - 1); ans = min(ans, tem); } printf("%d\n", ans); } return 0; }
Code(归并排序):
#include<cstdio> #include<cstdlib> #include<cmath> #include<cstring> #include<iostream> #include<algorithm> #include<string> #include<queue> #include<stack> #include<bitset> #include<set> #include<map> #include<cctype> #include<vector> //#define TEST #define LL long long #define Mt(f, x) memset(f, x, sizeof(f)); #define xep(i, n) for(int i = 0; i < (n); ++i) #define rep(i, s, e) for(int i = (s); i <= (e); ++i) #define dep(i, s, e) for(int i = (s); i >= (e); --i) #ifdef TEST #define See(a) cout << #a << " = " << a << endl; #define See2(a, b) cout << #a << " = " << a << ' ' << #b << " = " << b << endl; #define debug(a, s, e){ rep(_i, s, e) {cout << a[_i] << ' '; }cout << endl;} #define debug2(a, s, e, ss, ee) rep(i_, s, e) {debug(a[i_], ss, ee);} #else #define See(a) {} #define See2(a, b) {} #define debug(a, s, e) {} #define debug2(a, s, e, ss, ee) {} #endif const int MAX = 2e9; const int MIN = -2e9; const int PI = acos(-1.0); const double eps = 1e-9; using namespace std; const int N = 100000 + 5; int a , b ; int L[N >> 1], R[N >> 1]; int sum; void merge(int l, int r) { int m = (l + r) >> 1; if(l >= r) { return ; } merge(l, m); merge(m + 1, r); int left = 0, right = 0; rep(i, l, m) { L[left++] = a[i]; } rep(i, m + 1, r) { R[right++] = a[i]; } L[left] = R[right] = MAX; int t1 = 0, t2 = 0; rep(i, l, r) { if(L[t1] <= R[t2]) { a[i] = L[t1++]; } else { sum += left - t1; a[i] = R[t2++]; } } } int main() { int n; while(~scanf("%d", &n)) { sum = 0; xep(i, n) { scanf("%d", &a[i]); } memcpy(b, a, sizeof(a)); merge(0, n - 1); int ans = sum; xep(i, n) { sum = sum + (n - b[i] - 1) - b[i]; ans = min(ans, sum); } printf("%d\n", ans); } return 0; }
相关文章推荐
- HDU 1394- Minimum Inversion Number(线段树求逆序数)
- hdu 1394 Minimum Inversion Number - 树状数组
- Hdu 1394 Minimum Inversion Number
- HDU 1394 Minimum Inversion Number (线段树 单点更新 求逆序数)
- HDU 1394 Minimum Inversion Number(线段树:单点更新,求逆序数)
- HDU_1394_Minimum Inversion Number_线段树求逆序数
- [HDU 1394] Minimum Inversion Number 逆序对
- HDU 1394 Minimum Inversion Number(线段树:单点更新,区间求和)
- Minimum Inversion Number - HDU 1394 树状数组
- HDU 1394 (逆序数) Minimum Inversion Number
- hdu1394 Minimum Inversion Number(线段树)
- [HDU 1394]Minimum Inversion Number(归并排序/线段树)
- HDU 1394 Minimum Inversion Number
- hdu1394 Minimum Inversion Number
- hdu 1394 Minimum Inversion Number
- hdu1394 Minimum Inversion Number ——线段树入门题
- hdu 1394 Minimum Inversion Number(线段树)
- HDU 1394 Minimum Inversion Number
- HDU 1394 Minimum Inversion Number(单点更新)
- HDU 1394 Minimum Inversion Number