zoukankan      html  css  js  c++  java
  • HDU2838 Cow Sorting 树状数组 区间求和加逆序数的应用

    这题目意思非常easy,就是给你一个数组,然后让你又一次排好序,排序有要求的,每次仅仅能交换两个元素的位置,交换须要一个代价 就是两个元素之和,问你把数组重小到大排好最少须要多少代价


    可能一開始想不到逆序数,我是专门做专题往那边想才想到的,举个样例吧
    数组: 9 1 0 5 4
    此时到 0 的时候,我们先手写一下最小代价,然后再依照自己的推測去看看,就是当前扫到0,那么前面比它大的数有2个,所以先 部分代价为 2 * 0,然后再加上前面比它大的数 也就是9 和1 ,那么最小代价为10,发现跟手算的一样,那么 再多试几个 最后我们就发现了


    对于当前数num,前面有x个比它大的数,那么走到当前一步的 最小代价为 x*num 再加上前面比它大的数之和


    这样就非常easy跟树状数组扯上关系了,当前一步的逆序数 事实上就是  前面比它大的数的个数,然后同一时候又能用树状数组对于前面比它大的数求和,这样问题就完美攻克了,一開始我看n是10^5次,可能还是没经验把,认为有可能会超,所以就先离散化的做了一遍,但是总是WA,然后离散化去掉以后就过了,不知道为什么,但是用过掉的代码跑了非常多案例,发现跟离散化版本号的 答案是一样的,真心不知道哪里写错了

    离散化的贴出来,希望路过大神 指点:
    #include<iostream>
    #include<cstdio>
    #include<list>
    #include<algorithm>
    #include<cstring>
    #include<string>
    #include<stack>
    #include<map>
    #include<vector>
    #include<cmath>
    #include<memory.h>
    #include<set>
    #include<cctype>
    
    #define ll long long
    #define LL __int64
    #define eps 1e-8
    
    //const ll INF=9999999999999;
    
    #define inf 0xfffffff
    
    using namespace std;
    
    
    //vector<pair<int,int> > G;
    //typedef pair<int,int> P;
    //vector<pair<int,int>> ::iterator iter;
    //
    //map<ll,int>mp;
    //map<ll,int>::iterator p;
    
    const int N = 500000  + 10;
    
    
    int a[N];
    int aa[N];
    int n;
    
    typedef struct Node {
    	int v;//原数字
    	int id;//下标
    };
    
    Node p[N];
    
    typedef struct C {
    	LL sum;
    	int id;
    };
    
    C c[N];
    
    void clear() {
        memset(c,0,sizeof(c));
    	memset(aa,0,sizeof(aa));
    	memset(p,0,sizeof(p));
    }
    
    bool cmp(Node x,Node y) {
    	return x.v < y.v;
    }
    
    int lowbit(int x) {
        return x&(-x);
    }
    //设原始矩阵为a,将a[i]加上val时对c所做的改动
    void update(int i, int val) {
        while (i <= n) {
    		c[i].id += val;
            i += lowbit(i);
        }
    } 
    
    void add(int i,int val) {
    	while(i <= n) {
    		c[i].sum += (1LL) * val;
    		i += lowbit(i);
    	}
    }
    
    int get_sumid(int i) {
    	int sum = 0;
    	while(i > 0) {
    		sum += c[i].id;
    		i -= lowbit(i);
    	}
    	return sum;
    }
    
    
    //求前i项元素的和
    int get_sum(int i) {
        int sum=0;
        while (i > 0) {
            sum += c[i].sum;
            i -= lowbit(i);
        }
        return sum;
    }
    
    int main() {
        while(scanf("%d",&n) == 1) {
    		clear();
    		//先离散操作
    		for(int i=1;i<=n;i++) {
    			scanf("%d",&p[i].v);
    			a[i] = p[i].v;
    			p[i].id = i;//循环序号必须从1開始
    		}
    		sort(p + 1,p + n + 1,cmp);
    		for(int i=1;i<=n;i++)
    			aa[p[i].id] = i;//aa数组存了原来大小信息
    		LL ans = 0;
    		for(int i=1;i<=n;i++) {
    			update(aa[i],1);
    			add(a[i],a[i]);
    			int ans1 = i - get_sumid(aa[i]);//i代表当前已经插入的个数,ge_sum(aa[i])代表比aa[i]小的数个数,减去即为大的个数,即逆序数
    			if(ans1 != 0) {
    				LL ans2 = (1LL) * get_sum(n) - (1LL) * get_sum(a[i]);
    				ans += (1LL) * ans1 * a[i] + ans2;
    			}
    		}
    		printf("%I64d
    ",ans);
    	}
        return 0;
    }

    AC代码:

    #include<iostream>
    #include<cstdio>
    #include<list>
    #include<algorithm>
    #include<cstring>
    #include<string>
    #include<stack>
    #include<map>
    #include<vector>
    #include<cmath>
    #include<memory.h>
    #include<set>
    #include<cctype>
    
    #define ll long long
    #define LL __int64
    #define eps 1e-8
    
    //const ll INF=9999999999999;
    
    #define inf 0xfffffff
    
    using namespace std;
    
    
    //vector<pair<int,int> > G;
    //typedef pair<int,int> P;
    //vector<pair<int,int>> ::iterator iter;
    //
    //map<ll,int>mp;
    //map<ll,int>::iterator p;
    
    const int N = 500000  + 10;
    
    int n;
    
    typedef struct C {
    	LL sum;
    	int id;
    };
    
    C c[N];
    
    void clear() {
        memset(c,0,sizeof(c));
    }
    
    int lowbit(int x) {
        return x&(-x);
    }
    //设原始矩阵为a,将a[i]加上val时对c所做的改动
    void update(int i, int val) {
    	int j = i;
        while (i <= n) {
    		c[i].id += val;
    		c[i].sum += j;
            i += lowbit(i);
        }
    } 
    
    int get_sumid(int i) {
    	int sum = 0;
    	while(i > 0) {
    		sum += c[i].id;
    		i -= lowbit(i);
    	}
    	return sum;
    }
    
    
    //求前i项元素的和
    LL get_sum(int i) {
        LL sum=0;
        while (i > 0) {
            sum += c[i].sum;
            i -= lowbit(i);
        }
        return sum;
    }
    
    int main() {
        while(scanf("%d",&n) == 1) {
    		clear();
    		LL ans = 0;
    		for(int i=1;i<=n;i++) {
    			int x;
    			scanf("%d",&x);
    			update(x,1);
    			LL ans1 = i - get_sumid(x);//i代表当前已经插入的个数,ge_sum(aa[i])代表比aa[i]小的数个数,减去即为大的个数,即逆序数
    			if(ans1 != 0) {
    				LL ans2 = get_sum(n) - (1LL) * get_sum(x);
    				ans += ans1 * x + ans2;
    			}
    		}
    		printf("%I64d
    ",ans);
    	}
        return 0;
    }
    
    
    
    /*
    4
    1 3 2 4
    
    5
    1 5 3 2 4
    
    5
    5 4 3 2 1
    
    7 
    3 4 5 1 2 7 6
    
    6
    2 1 6 5 4 3
    
    7
    4 3 6 5 2 1 7
    
    ans:
    5
    29
    60
    46
    57
    69
    */
    




  • 相关阅读:
    The Elements of C# Style Design
    The Elements of C# Style Programming
    The Elements of C# Style General Principles
    浅谈CLR
    堆排序
    WPF系列:GridView列绑定控件(一)
    分发服务器迁移(distribute service migration‏)
    通过编码规范来学习一门编程语言
    如何维护数据库中的静态表
    关于短地址服务的一些看法
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/3767892.html
Copyright © 2011-2022 走看看