洛谷 P1966 火柴排隊 解題報告
阿新 • • 發佈:2018-08-06
efi 不容易 con scan can void 逆序對 return gin
\(maxlongint\)
P1966 火柴排隊
題目描述
涵涵有兩盒火柴,每盒裝有 \(n\) 根火柴,每根火柴都有一個高度。 現在將每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 兩列火柴之間的距離定義為: \(\sum (a_i-b_i)^2\)其中 \(a_i\) 表示第一列火柴中第 \(i\) 個火柴的高度, \(b_i\) 表示第二列火柴中第 \(i\) 個火柴的高度。
每列火柴中相鄰兩根火柴的位置都可以交換,請你通過交換使得兩列火柴之間的距離最小。請問得到這個最小的距離,最少需要交換多少次?如果這個數字太大,請輸出這個最小交換次數對 \(99,999,997\) 取模的結果。
輸入輸出格式
輸入格式:
共三行,第一行包含一個整數 \(n\) ,表示每盒中火柴的數目。
第二行有 \(n\) 個整數,每兩個整數之間用一個空格隔開,表示第一列火柴的高度。
第三行有 \(n\) 個整數,每兩個整數之間用一個空格隔開,表示第二列火柴的高度。
輸出格式:
一個整數,表示最少交換次數對 \(99,999,997\) 取模的結果。
數據範圍
對於 \(10\%\) 的數據, \(1 ≤ n ≤ 10\);
對於 \(30\%\) 的數據, \(1 ≤ n ≤ 100\) ;
對於 \(60\%\) 的數據, \(1 ≤ n ≤ 1,000\) ;
對於 \(100\%\) 的數據, \(1 ≤ n ≤ 100,000\),\(0≤\) 火柴高度 \(≤\)
感覺蠻神奇的一道題目。
玩一下我們感覺,兩邊第\(i\)大的相互對著是最優的。
證明可以先拆平方,然後利用鄰項交換證明最優性。
離散一下,我們發現其實就是求逆序對。
處理起來可能比較麻煩,但把所有數組都搞出來反而不容易錯。
Code:
#include <cstdio> #include <algorithm> #define ll long long const int N=100010; struct node { int pos;ll h; bool friend operator <(node n1,node n2) { return n1.h<n2.h; } }a[N],b[N]; ll s[N],c[N],d[N],e[N],f[N],ans; int n; ll query(int x) { ll sum=0; while(x) { sum+=s[x]; x-=x&-x; } return sum; } void add(int x) { while(x<=n) { s[x]++; x+=x&-x; } } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%lld",&a[i].h); a[i].pos=i; } for(int i=1;i<=n;i++) { scanf("%lld",&b[i].h); b[i].pos=i; } std::sort(a+1,a+1+n); std::sort(b+1,b+1+n); for(int i=1;i<=n;i++) { c[a[i].pos]=i; d[b[i].pos]=i; } for(int i=1;i<=n;i++) e[d[i]]=i; for(int i=1;i<=n;i++) f[i]=e[c[i]]; for(int i=1;i<=n;i++) { (ans+=query(n)-query(f[i]))%=99999997; add(f[i]); } printf("%lld\n",ans); return 0; }
2018.8.5
洛谷 P1966 火柴排隊 解題報告