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,然后离散化去掉以后就过了,不知道为什么,但是用过掉的代码跑了非常多案例,发现跟离散化版本号的 答案是一样的,真心不知道哪里写错了
可能一開始想不到逆序数,我是专门做专题往那边想才想到的,举个样例吧
数组: 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\n",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\n",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 */