【数学建模】【APIO2015】Palembang Bridges
Description
?一條東西走向的穆西河將巴鄰旁市一分為二,分割成了區域 A 和區域 B。
每一塊區域沿著河岸都建了恰好 1000000001 棟的建筑,每條岸邊的建筑都從 0 編號到 1000000000。相鄰的每對建筑相隔 1 個單位距離,河的寬度也是 1 個單位長度。區域 A 中的 i 號建筑物恰好與區域 B 中的 i 號建筑物隔河相對。 城市中有 N 個居民。第 i 個居民的房子在區域 Pi 的 Si 號建筑上,同時他的辦公室坐落在 Qi 區域的 Ti 號建筑上。一個居民的房子和辦公室可能分布在河的兩岸,這樣他就必須要搭乘船只才能從家中去往辦公室,這種情況讓很多人都覺得不方便。為了使居民們可以開車去工作,政府決定建造不超過 K 座橫跨河流的大橋。 由于技術上的原因,每一座橋必須剛好連接河的兩岸,橋梁必須嚴格垂直于河流,并且橋與橋之間不能相交。當政府建造最多 K 座橋之后,設 Di 表示第 i 個居民此時開車從家里到辦公室的最短距離。請幫助政府建造橋梁,使得 D1+D2+?+DN 最小。Input
輸入的第一行包含兩個正整數 K 和 N,分別表示橋的上限數量和居民的數量。
接下來 N 行,每一行包含四個參數:Pi,Si,Qi 和 Ti,表示第 i 個居民的房子在區域 Pi 的 Si 號建筑上,且他的辦公室位于 Qi 區域的 Ti 號建筑上。Output
輸出僅為一行,包含一個整數,表示 D1+D2+?+DN 的最小值。
Sample Input
1 5B 0 A 4
B 1 B 3
A 5 B 7
B 2 A 6
B 1 A 7
Sample Output
24HINT
K=1或K=2
1≤N≤100000題解
/*自己搞出來的一道題,真是好感動*/
為了方便,在同一側的直接處理掉。
K=1時,顯然就是取中位數。
K=2時,考慮每一對(S,T),(綠藍代表兩座橋),那么肯定是要選兩條紅線短的那一邊。不過這樣還不夠好考慮,我們不如讓著兩條直線伸長相等的距離,延伸到中點。
于是對于每一對(S,T),直接看Mid到兩墻的距離就可以選擇了。
進一步得出,如果我們把它們按中點排序,那么最后的局面肯定是,左部分都去橋1,右部分都去橋2,有一個分割點。
那么我們可以枚舉分割點,分別計算兩部分的最優橋,很神奇的把K=2分成了兩個K=1,得到n^2的算法。
顯然最優橋我們是可以動態維護的。
考慮點i(一對ST),把它從右部分加入左部分。
那么它對于最優橋的影響是可以討論的,過程很傻逼可以自己試一試。
我得到的結果是,考慮左右部分肯定都是偶數,那么另左部分中位數取(len/2),右部分中位數取(len/2+1),這么做比較方便。
然后加點到左部分的時候,因為我們已經按中點排序,所以只可能是一左一右或者兩右(左右是相對當前最優橋而言的)。
那么如果是一左一右,最優橋不發生變化,對ans新的貢獻也就是這個點的貢獻。
如果是兩右,會使最優橋右移一位,但對于之前已加入的點是沒有影響的,ans的改變還是只有這個點。
于是用兩個樹狀數組模擬兩邊,每次求最優橋(這個也用樹狀數組求第k小數),然后維護ans也就是計算當前點的影響就行了。
復雜度O(nlogn)。說不清還是看代碼吧。
主要考察數學建模、對數據結構的應用,感覺這題還是蠻好的。
?
代碼
代碼能力各種逗啊QwQ 調了好久 但調出來后真是好久沒覺得這么爽了
#include<cstdio> #include<algorithm> #define ll long long using namespace std; const int maxn=1e5+5;int abs(int x){return x>0?x:-x;}struct point{int x,y,idx,idy,mid;bool operator <(const point&aa)const {return mid<aa.mid;} }a[maxn];int b[maxn*2],l,len,k,n; ll ans;void prepare(){for(int i=1;i<=l;i++)b[++len]=a[i].x,b[++len]=a[i].y;sort(b+1,b+len+1);for(int i=1;i<=l;i++){if(a[i].x>a[i].y) swap(a[i].x,a[i].y);a[i].idx=lower_bound(b+1,b+len+1,a[i].x)-b;a[i].idy=lower_bound(b+1,b+len+1,a[i].y)-b;} }int S1[maxn*2],S2[maxn*2];int lowbit(int o){return o&-o;} int add(int o,int k,int* C){while(o<=len){C[o]+=k;o+=lowbit(o);} }int find(int k,int *C){int ret=0,cnt=0;for(int i=17;i>=0;i--){ret+=(1<<i);if(ret>len||cnt+C[ret]>=k) ret-=(1<<i);else{cnt+=C[ret];}}return ret+1; }ll solve(){ll ans1=0,ans2=0,ansx=0;prepare();int A=0,B=b[len/2+1];for(int i=1;i<=len;i++)ans2+=abs(B-b[i]);for(int i=1;i<=l;i++)add(a[i].idx,1,S2),add(a[i].idy,1,S2);ansx=ans2;for(int i=1;i<=l;i++){int l1=i*2,l2=len-i*2;add(a[i].idx,1,S1);add(a[i].idy,1,S1);add(a[i].idx,-1,S2);add(a[i].idy,-1,S2);ans2-=abs(a[i].x-B)+abs(a[i].y-B);A=b[find(l1/2,S1)],B=b[find(l2/2+1,S2)];ans1+=abs(a[i].x-A)+abs(a[i].y-A);if(ans1+ans2<ansx) ansx=ans1+ans2;}return ansx; }int main(){char p,q;int u,v;scanf("%d%d",&k,&n);if(k==1){ans=n;for(int i=1;i<=n;i++){scanf("\n%c %d %c %d",&p,&u,&q,&v);if(p==q) ans+=abs(u-v),ans--;else b[++l]=u,b[++l]=v;}sort(b+1,b+l+1);int A=b[l/2];for(int i=1;i<=l;i++)ans+=abs(A-b[i]);printf("%lld\n",ans);}else{ans=n;for(int i=1;i<=n;i++){l++;scanf("\n%c %d %c %d",&p,&a[l].x,&q,&a[l].y);if(p==q) ans+=abs(a[l].x-a[l].y)-1,l--;else a[l].mid=a[l].x+a[l].y;}sort(a+1,a+l+1);printf("%lld",ans+solve());}return 0; }?
?
轉載于:https://www.cnblogs.com/xkui/p/4536421.html
總結
以上是生活随笔為你收集整理的【数学建模】【APIO2015】Palembang Bridges的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 什么是红色车牌?
- 下一篇: 使用nginx进行负载均衡