題目描述
涵涵有兩盒火柴,每盒裝有 n 根火柴,每根火柴都有乙個高度。 現在將每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 兩列火柴之間的距離定義為:∑(ai−bi)^2
其中 ai 表示第一列火柴中第 i 個火柴的高度,bi 表示第二列火柴中第 i 個火柴的高度。
每列火柴中相鄰兩根火柴的位置都可以交換,請你通過交換使得兩列火柴之間的距離最小。請問得到這個最小的距離,最少需要交換多少次?如果這個數字太大,請輸出這個最小交換次數對 10^8-3 取模的結果。
輸入格式
共三行,第一行包含乙個整數 n,表示每盒中火柴的數目。
第二行有 n 個整數,每兩個整數之間用乙個空格隔開,表示第一列火柴的高度。
第三行有 n 個整數,每兩個整數之間用乙個空格隔開,表示第二列火柴的高度。
輸出格式
乙個整數,表示最少交換次數對 10^8-3 取模的結果。
首先要推這個式子 ∑(ai−bi)^2=∑(ai ^2+bi ^2-2aibi) 可以發現ai ^2+bi ^2總和是不變,只要找到ai*bi的最大值;
可以發現,當ai和bi都是公升序排列的時候,ai*bi是最大的;
所以可以把ai和bi都離散化以後,以ai為序列當做公升序模板,把bi的排列變為ai的排列順序;
可以想到這裡就是求逆序對了;
很多求解法,我用的是權值線段樹;
**:
#include
#define ll long long
#define pa pair
#define ls k<<1
#define rs k<<1|1
#define inf 0x3f3f3f3f
using
namespace std;
const
int n=
100010
;const
int m=
2000100
;const ll mod=
1e8-3;
int n,a[n]
,a1[n]
,b[n]
,b1[n]
,sum,pos[n]
;ll ans;
struct nodetr[n*4]
;void
build
(int l,
int r,
int k)
int d=
(l+r)
>>1;
build
(l,d,ls)
;build
(d+1
,r,rs)
; tr[k]
.w=tr[ls]
.w+tr[rs]
.w;}
void
add(
int p,
int k)
int d=
(tr[k]
.l+tr[k]
.r)>>1;
if(p<=d)
add(p,ls)
;else
add(p,rs)
; tr[k]
.w=tr[ls]
.w+tr[rs]
.w;}
void
query
(int ll,
int rr,
int k)
int d=
(tr[k]
.l+tr[k]
.r)>>1;
if(ll<=d)
query
(ll,rr,ls);if
(rr>d)
query
(ll,rr,rs);}
intmain()
for(
int i=
1;i<=n;i++
) pos[a[i]
]=i;
build(1
,n,1);
for(
int i=
1;i<=n;i++
) cout
}
洛谷P1966 火柴排隊 逆序對
題目鏈結 不算很難的一道題 首先要保證權值最小,不難想到一種貪心策略,即把兩個序列中rank相同的數放到同乙個位置 證明也比較trivial。假設 a 中有兩個元素 a,b b 中有兩個元素 c,d 然後分別討論一下當 a b 時 c 與 a 對應優還是與 b 對應優。化簡的時候直接對兩個式子做差。...
洛谷1966 火柴排隊(逆序對)
點此看題面 大致題意 有 a 和 b 兩個陣列,問你要將 b 進行多少次相鄰兩數交換操作,才能使得 sum n a i b i 2 最小。不難猜到,當 a 中第 i 小的數與 b 中第 i 小的數配對時,值最小。證明以 n 2 為例 n 2 同理 設 a 1,此時只有兩種匹配方式 s 1 a 1 b...
洛谷 P1966 火柴排隊(樹狀陣列求逆序)
涵涵有兩盒火柴,每盒裝有 nn 根火柴,每根火柴都有乙個高度。現在將每盒中的火柴各自排成一列,同一列火柴的高度互不相同,兩列火柴之間的距離定義為 其中 a iai 表示第一列火柴中第 ii 個火柴的高度,b ibi 表示第二列火柴中第 ii 個火柴的高度。每列火柴中相鄰兩根火柴的位置都可以交換,請你...