hdoj 5497 Inversion 【树状数组维护 区间逆序对】

来源:互联网 发布:linux 网卡网关 编辑:程序博客网 时间:2024/04/29 17:15



Inversion

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 360    Accepted Submission(s): 93


Problem Description
You have a sequence {a1,a2,...,an} and you can delete a contiguous subsequence of length m. So what is the minimum number of inversions after the deletion.
 

Input
There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:

The first line contains two integers n,m(1n105,1m<n) - the length of the seuqence. The second line contains n integers a1,a2,...,an(1ain).

The sum of n in the test cases will not exceed 2×106.
 

Output
For each test case, output the minimum number of inversions.
 

Sample Input
23 11 2 34 24 1 3 2
 

Sample Output
01
 


断网断电一天了,醉了。。。


题意:给一个N个数组成的序列a[](a[i] <= N),让你从中删去长度为M的连续子序列使得剩余序列的逆序对最少,输出最少的逆序对。


分析:对一个序列而言

删除(插入)一个元素a[i]逆序对减少(增加)—— 

序列中在a[i]前面比a[i]大的元素个数 + 序列中在a[i]后面比a[i]小的元素个数


思路:选择一个初始状态(我选择的是去掉前M个元素的状态),用树状数组求出该状态的逆序对数目。然后枚举下面所有状态,用两个树状数组每次计算删除最右一个元素插入最左一个元素所得到的逆序对数目,维护这个最小值就可以了。


AC代码:


#include <cstdio>#include <cstring>#include <algorithm>#define MAXN 100000+10#define INF 0x3f3f3f3f#define LL long longusing namespace std;int C1[MAXN], C2[MAXN];int a[MAXN];int N, M;int lowbit(int x){    return x & (-x);}void update(int x, int d, int *C){    while(x <= N)    {        C[x] += d;        x += lowbit(x);    }}int query_sum(int x, int *C){    int s = 0;    while(x > 0)    {        s += C[x];        x -= lowbit(x);    }    return s;}int main(){    int t;    scanf("%d", &t);    while(t--)    {        scanf("%d%d", &N, &M);        for(int i = 1; i <= N; i++)            scanf("%d", &a[i]);        LL ans = 0;        memset(C1, 0, sizeof(C1));//统计前面有多少个数比它大        memset(C2, 0, sizeof(C2));//统计后面有多少个数比它小        for(int i = N; i > M; i--)        {            update(a[i], 1, C1);            ans += query_sum(a[i]-1, C1);//初始状态        }        LL cnt = ans;        for(int i = M+1; i <= N; i++)        {            //减少数目            int sub = query_sum(a[i]-1, C1) + query_sum(N, C2) - query_sum(a[i], C2);            update(a[i], -1, C1);//去掉置0            update(a[i-M], 1, C2);//增加置1            //增加数目            int add = query_sum(a[i-M]-1, C1) + query_sum(N, C2) - query_sum(a[i-M], C2);            //printf("sub - %d  add - %d\n", sub, add);            cnt = cnt - sub + add;            ans = min(ans, cnt);        }        printf("%lld\n", ans);    }    return 0;}


0 0
原创粉丝点击