題目鏈結:
題目大意:每頭牛有個憤怒值,每次交換相鄰兩個數進行公升序排序,$cost=val_+val_$,求$\min \sum cost_$
解題思路:
按輸入順序dp:
第i的值val的最小cost=當前數的逆序數個數*val+當前數的逆序數和
相當於每次只把這個val同逆序的數做交換,$\sum val_=rev*val$ , $\sum val_=\sum rev$
無後效性原則體現在,當前計算的cost只於前面的數有關,而且對順序沒有影響(逆序數隨你怎麼排了)
求逆序數個數和逆序數和都可以通過樹狀陣列在$o(logn)$內完成
樹狀陣列對於每個val,$update(val,1)$,即每個val點的值是1
這樣$rev=i-getindex(val)$
原理是,樹狀陣列是按從小到大維護的,輸入順序i(從1開始)-前面數個數(包含自身)=本來應該在後面,卻跑到前面數的個數
本題的乙個trick就是val不可重,所以$update(val,val)$ ,即每個val點的值是val
這樣$\sum=getsum(n)-getsum(val)$,即整個序列已經更新的值和(i~n此時都是0)-當前值前面的和=逆序數和
#include "cstdio
"#include
"map
"#include
"cstring
"#include
"algorithm
"using
namespace
std;
#define ll long long
#define maxn 100005ll sum[maxn],index[maxn];
intval,n;
int lowbit(int x)
ll getsum(
intx)
return
ret;
}ll getindex(
intx)
return
ret;
}void update(int x,int s,int
idx)
}int
main()
printf(
"%i64d\n
",ans);
}}
樹狀陣列 hdu2689 hdu2838
題意 給定乙個正整數n,和乙個1 n的乙個排列,每個數可以和旁邊的兩個數的任意乙個交換,每交換一次總次數就要加一,問將這個排列轉換成乙個遞增的排列需要多少次交換?題意可以轉換成求這個排列的逆序對數。include include include include using namespace std...
hdu 2838 樹狀陣列水題
提議是給你乙個序列 讓你調整把它變成 從小到大排列的有序序列 沒調動兩個為兩權值之和 問最小的權值和是多少 給個數列 1 4 2 3 5 對每乙個位置數 需要交換的比為前面比它大的數 或後面比它小的數 包含了最小值在裡面了 比如pi前面有5個數比它大 則就需要把這5個數和pi交換 交換的權值就是這5...
hdu 2227 樹狀陣列 dp
題意是求乙個數列的不遞減的子串行的個數 很顯然,如果只用dp來做的話時間是o n n 因為dp i 為前i個數可能的方案,則狀態轉移方程為dp i sum dp j j 先對num按數來進行排序,這道題因為資料較大 用到了離散化 因為更新是是按原序更新的,及i之前的num j 一定比num i 小,...