這題目意思很簡單,就是給你一個數組,然後讓你重新排好序,排序有要求的,每次只能交換兩個元素的位置,交換需要一個代價 就是兩個元素之和,問你把數組重小到大排好最少需要多少代價
可能一開始想不到逆序數,我是專門做專題往那邊想才想到的,舉個例子吧
數組: 9 1 0 5 4
此時到 0 的時候,我們先手寫一下最小代價,然後再按照自己的猜測去看看,就是當前掃到0,那麼前面比它大的數有2個,所以先 部分代價為 2 * 0,然後再加上前面比它大的數 也就是9 和1 ,那麼最小代價為10,發現跟手算的一樣,那麼 再多試幾個 最後我們就發現了
對於當前數num,前面有x個比它大的數,那麼走到當前一步的 最小代價為 x*num 再加上前面比它大的數之和
這樣就很容易跟樹狀數組扯上關係了,當前一步的逆序數 其實就是 前面比它大的數的個數,然後同時又能用樹狀數組對於前面比它大的數求和,這樣問題就完美解決了,一開始我看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 0xfffffffusing 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 0xfffffffusing 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;}/*41 3 2 451 5 3 2 455 4 3 2 17 3 4 5 1 2 7 662 1 6 5 4 374 3 6 5 2 1 7ans:52960465769*/