洛谷p1966 火柴排隊 (逆序對變形,目標排序

2022-05-13 15:52:27 字數 3204 閱讀 3289

涵涵有兩盒火柴,每盒裝有 n 根火柴,每根火柴都有乙個高度。 現在將每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 兩列火柴之間的距離定義為: ∑(ai-bi)^2

其中 ai 表示第一列火柴中第 i 個火柴的高度,bi 表示第二列火柴中第 i 個火柴的高度。

每列火柴中相鄰兩根火柴的位置都可以交換,請你通過交換使得兩列火柴之間的距離最小。請問得到這個最小的距離,最少需要交換多少次?如果這個數字太大,請輸出這個最小交換次數對 99,999,997 取模的結果。

輸入格式:

輸入檔案為 match.in。

共三行,第一行包含乙個整數 n,表示每盒中火柴的數目。

第二行有 n 個整數,每兩個整數之間用乙個空格隔開,表示第一列火柴的高度。

第三行有 n 個整數,每兩個整數之間用乙個空格隔開,表示第二列火柴的高度。

輸出格式:

輸出檔案為 match.out。

輸出共一行,包含乙個整數,表示最少交換次數對 99,999,997 取模的結果。

輸入樣例#1:

【輸入輸出樣例 1】

42 3 1 4

3 2 1 4

【輸入輸出樣例 2】

41 3 4 2

1 7 2 4

輸出樣例#1:

【輸入輸出樣例 1】

1【輸入輸出樣例 2】

2

【輸入輸出樣例說明1】

最小距離是 0,最少需要交換 1 次,比如:交換第 1 列的前 2 根火柴或者交換第 2 列的前 2 根火柴。

【輸入輸出樣例說明2】

最小距離是 10,最少需要交換 2 次,比如:交換第 1 列的中間 2 根火柴的位置,再交換第 2 列中後 2 根火柴的位置。

【資料範圍】

對於 10%的資料, 1 ≤ n ≤ 10;

對於 30%的資料,1 ≤ n ≤ 100;

對於 60%的資料,1 ≤ n ≤ 1,000;

對於 100%的資料,1 ≤ n ≤ 100,000,0 ≤火柴高度≤ maxlongint

這個題貪心的證明

假設第一列有兩個數 a,b(a < b) 第二列有兩個數 x,y(x < y)

那麼看(a-x)^2+(b-y)^2與(a-y)^2+(b-x)^2哪個更小,哪個就更優

可以假設左邊《右邊,然後化簡,將兩邊的二次方都去掉

化簡後得 -ax-by < -ay-bx

再次移項得到 a(x-y)>b(x-y) 由於x-y是負數,化簡後得 a < b,式子成立(意思就是如果左邊》右邊的話就與條件矛盾了)

那麼顯然小的配小的,大的配大的最優

那麼我們目標就是a的第一大和b的第一大在一塊,a的第i大和b的第i大在一塊

那麼我們可以固定一端移動另外一端,

固定a移動b,那麼我們發現移動的時候按b的第幾大為關鍵字進行移動,那麼值為1的數不一定要移動到1這個位置

因為1這個下標索引不一定是a的第一大

所以我們發現乙個顯然成立的事實,那就是從乙個亂序陣列排序成有序陣列的最少交換次數和乙個有序陣列還原成亂序陣列的最小交換次數相同

那麼就相當於,當前已經按目標位置排好序的序列到原位置的最少交換次數=原序列到各自移動到目標位置的序列的最少交換次數

因為等式右邊難於實現,所以選擇等價的左邊的實現,先讓他跑到應該到的位置,然後跑回原位,這就是解決方法(有點像時光倒流哦

附上** (套自己的模板所以有點長

1 #include 2 #include 3 #include 4 #include 5

using

namespace

std;

6const

int maxn=1e5+7;7

intn,w;

8 typedef long

long

ll;9

ll t[maxn],q[maxn];

10struct

node;node(int id,int

v):id(id),v(v){};

12};

13node a[maxn],b[maxn];

14int lowbit(int

x)17

void add(int n,int

x)22

}23 ll sum(int

n)29

return

ans;30}

31bool

cmp1(node a,node b)

34bool

cmp2(node a,node b)

37int

main()

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

47 sort(a+1,a+1+n,cmp1);

48 sort(b+1,b+1+n,cmp1);

49int cnt=1,st=1,pre=a[1

].v;

50for(int i=2;i<=n;++i)

55 st=i;pre=a[i].v;

56 cnt++;57}

58for(int j=st;j<=n;++j) a[j].v=cnt;

59//

for(int i=1;i<=n;++i) printf("%d,",a[i].v);printf("\n");

60 cnt=1,st=1,pre=b[1

].v;

61for(int i=2;i<=n;++i)

66 st=i;pre=b[i].v;

67 cnt++;68}

69for(int j=st;j<=n;++j) b[j].v=cnt;

70//

for(int i=1;i<=n;++i) printf("%d,",b[i].v);printf("\n");

71//

sort(a+1,a+1+n,cmp2);sort(b+1,b+1+n,cmp2);

72 n=n;

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

76 ll ans=0;77

for(int i=n;i>=1;--i)

81 printf("

%lld\n

",ans);

82return0;

83 }

view code

為什麼按值排序呢,因為我們要對排名相同的配對,這是我們要的目標序列

洛谷P1966 火柴排隊 逆序對

題目鏈結 不算很難的一道題 首先要保證權值最小,不難想到一種貪心策略,即把兩個序列中rank相同的數放到同乙個位置 證明也比較trivial。假設 a 中有兩個元素 a,b b 中有兩個元素 c,d 然後分別討論一下當 a b 時 c 與 a 對應優還是與 b 對應優。化簡的時候直接對兩個式子做差。...

洛谷 P1966 火柴排隊

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

洛谷P1966 火柴排隊

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