洛谷 P1966 火柴排隊 題解
此文為博主原創題解,轉載時請通知博主,並把原文鏈接放在正文醒目位置。
題目鏈接:https://www.luogu.org/problem/show?pid=1966
題目描述
涵涵有兩盒火柴,每盒裝有 n 根火柴,每根火柴都有一個高度。 現在將每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 兩列火柴之間的距離定義為: ∑(ai-bi)^2
其中 ai 表示第一列火柴中第 i 個火柴的高度,bi 表示第二列火柴中第 i 個火柴的高度。
每列火柴中相鄰兩根火柴的位置都可以交換,請你通過交換使得兩列火柴之間的距離最小。請問得到這個最小的距離,最少需要交換多少次?如果這個數字太大,請輸出這個最小交換次數對 99,999,997 取模的結果。
輸入輸出格式
輸入格式:輸入文件為 match.in。
共三行,第一行包含一個整數 n,表示每盒中火柴的數目。
第二行有 n 個整數,每兩個整數之間用一個空格隔開,表示第一列火柴的高度。
第三行有 n 個整數,每兩個整數之間用一個空格隔開,表示第二列火柴的高度。
輸出格式:輸出文件為 match.out。
輸出共一行,包含一個整數,表示最少交換次數對 99,999,997 取模的結果。
輸入輸出樣例
輸入樣例#1:4 2 3 1 4 3 2 1 4輸出樣例#1:
1輸入樣例#2:
4 1 3 4 2 1 7 2 4
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中次大……
(然後忘記了老師是怎麽講的)
總之就是對a進行一下離散化,用rank數組對應a,b的編號,然後求逆序對即為答案。
AC代碼:
1 #include<cstdio> 2 #include<algorithm> 3 #include<cmath> 4 #include<cstring> 5 6 const int MOD = 99999997; 7 const int MAXN = 100005; 8 9 inline void read(int &x) 10 { 11 char ch = getchar(),c = ch;x = 0; 12 while(ch < ‘0‘ || ch > ‘9‘) c = ch,ch = getchar(); 13 while(ch <= ‘9‘ && ch >= ‘0‘) x = (x<<1)+(x<<3)+ch-‘0‘,ch = getchar(); 14 if(c == ‘-‘) x = -x; 15 } 16 17 int n,rank[MAXN]; 18 long long ans; 19 20 struct NUM 21 { 22 int ord,v; 23 }a[MAXN],b[MAXN]; 24 25 int cmp(NUM a,NUM b) 26 {return a.v < b.v;} 27 28 inline int lowbit(int x) 29 {return x&(-x);} 30 31 inline void update(int x,int num) 32 { 33 while(x <= n) 34 { 35 c[x] += num; 36 x += lowbit(x); 37 } 38 } 39 40 inline int sum(int x) 41 { 42 int sum = 0; 43 while(x > 0) 44 { 45 sum += c[x]; 46 x -= lowbit(x); 47 } 48 return sum; 49 } 50 int main() 51 { 52 read(n); 53 for(register int i = 1;i <= n;++ i) 54 read(a[i].v),a[i].ord = i; 55 for(register int i = 1;i <= n;++ i) 56 read(b[i].v),b[i].ord = i; 57 std::sort(a+1,a+1+n,cmp); 58 std::sort(b+1,b+1+n,cmp); 59 for(register int i = 1;i <= n;++ i) 60 rank[a[i].ord] = b[i].ord; 61 for(register int i = 1;i <= n;++ i) 62 { 63 update(rank[i],1); 64 ans = (ans + i - sum(rank[i]))%MOD; 65 } 66 printf("%lld\n",ans); 67 return 0; 68 }
洛谷 P1966 火柴排隊 題解