P1966 火柴排隊

2021-08-28 13:30:18 字數 1977 閱讀 7383

題意:求兩個為n的序列貢獻值最小需要怎麼移動才能達到,移動:交換相鄰元素,貢獻值:(ai-bi)^2。

顯然可以猜出來,排序過後對應的最小。

事實上也可以用反證法證明aac+bd最小

我們令上面的序列不動,只動下面的序列,首先得到下面序列應該是怎麼樣的。

用標號來標誌原來位置,排序過後,把對應位置賦值到陣列上去:上面位置是座標,下面位置是值。

而原來是1~n的有序序列,我把其排序的交換次數和把它變成特定這樣順序的交換次數顯然一樣。

直接判斷逆序對數,即可判斷交換次數。

#include#include#include#include#include#include#include#include#include#define rep(a,b) for(register int i=a;i<=b;i++)

#define red(a,b) for(register int i=a;i>=b;i--)

#define ull unsigned long long

#define ll long long

using namespace std;

ll sum[200050];

ll lowbit(int x)

//返回最小的值

void update(int pos,ll val,int d)//單點修改

}//維護的是字首和

ll query(int pos)

return s;

}//就算是前面的更新,也只是把需要用到的更新了,求區間和的時候需要按1的位置加起來。

ll arra[100050],arrb[100050];

struct node

arr[200100],brr[200010];

int crr[200010];

int cmp(node a,node b)

rep(1,n)

sort(arr+1,arr+1+n,cmp);

sort(brr+1,brr+1+n,cmp);

rep(1,n)

ll s=0;

rep(1,n)

cout<歸併排序:

利用每次排序過程中對於右側的一半,如果出現較小的數,會對逆序對有貢獻:每次要填入右側的數的時候,說明左側開始直到左側結束的所有數都比它大。

遞迴一層層從小部分到大部分。從而處理到每一部分對應的逆序對。(右側對應左側)

#includeusing namespace std;

const int mod = 99999997;

struct node

a[1000010],b[1000010];

int n;

int c[1000010];

int temp[1000010];

long long ans=0;

int split_up(node a,node b)

}while(i<=mid)temp[++cnt]=c[i++];

while(j<=r)temp[++cnt]=c[j++];

for(int i=l;i<=r;i++)

}int main()

for(int i=1;i<=n;i++)

sort(a+1,a+1+n,split_up);

sort(b+1,b+1+n,split_up);

for(int i=1;i<=n;i++)

c[a[i].index]=b[i].index;

operate(1,n);

cout

}

P1966 火柴排隊

讓a,b序列中大小排名相對應即可 若a中第j大的位於i,則應該b中第j大位於i 證明 假如a1則排列方式有 a1,a2,b1,b2或 a1,a2,b2,b1那麼 對於這兩種情況上,平方並做差,即可得以上結論 然而大問題是這樣離散化後怎麼搞出交換幾次呢 離散化後 c b i 然後若我們最後拍完序 定然...

P1966 火柴排隊

題目描述 涵涵有兩盒火柴,每盒裝有 nn 根火柴,每根火柴都有乙個高度。現在將每盒中的火柴各自排成一列,同一列火柴的高度互不相同,兩列火柴之間的距離定義為 sum a i b i 2 a i b i 2 其中 a i 表示第一列火柴中第 i 個火柴的高度,b i 表示第二列火柴中第 i 個火柴的高度...

P1966 火柴排隊

涵涵有兩盒火柴,每盒裝有 n 根火柴,每根火柴都有乙個高度。現在將每盒中的火柴各自排成一列,同一列火柴的高度互不相同,兩列火柴之間的距離定義為 ai bi 2 其中ai 表示第一列火柴中第 i個火柴的高度,bi 表示第二列火柴中第 i 個火柴的高度。每列火柴中相鄰兩根火柴的位置都可以交換,請你通過交...