1. 程式人生 > >BZOJ 3714: [PA2014]Kuglarz

BZOJ 3714: [PA2014]Kuglarz

個人 快排 fin 策略 %d () cor 奇偶性 但是

呃。。好像棄坑了好久=v=。。本來打算在bzoj每刷10題合起來寫一份題解。。但是1個月好像還刷不到10題的樣子(水題除外),所以還是單獨寫一下題解。。

Description

魔術師的桌子上有n個杯子排成一行,編號為1,2,…,n,其中某些杯子底下藏有一個小球,如果你準確地猜出是哪些杯子,你就可以獲得獎品。花費c_ij元,魔術師就會告訴你杯子i,i+1,…,j底下藏有球的總數的奇偶性。
采取最優的詢問策略,你至少需要花費多少元,才能保證猜出哪些杯子底下藏著球?

Input

第一行一個整數n(1<=n<=2000)。
第i+1行(1<=i<=n)有n+1-i個整數,表示每一種詢問所需的花費。其中c_ij(對區間[i,j]進行詢問的費用,1<=i<=j<=n,1<=c_ij<=10^9)為第i+1行第j+1-i個數。

Output

輸出一個整數,表示最少花費。

Sample Input

5
1 2 3 4 5
4 3 2 1
3 4 5
2 1
5

Sample Output

7 題目大意:自行理解。。 算法:前綴和+最小生成樹+奇技淫巧? 看到這題立刻就想到可以把每個杯底下是否有球看成一個01狀態。。然後想了一個用前綴和貪心的辦法。。然而行不通。。 然後默默翻開了題解。。 看的一臉懵逼。。 最後看懂了。。 因為要知道所有情況,所以要將這個01序列通過前綴和分成n塊,那麽就是怎麽分割的問題了。。 所以可以抽象成一個圖,知道i到j奇偶性的代價就是i連到j的邊權,因為前綴和有0,所以n+1個點,連成最小代價,那麽就是求這n+1個點的最小生成樹了。。
只需要在讀入的時候連一下邊,然後跑一遍kruskal就好辣.>v<(表示撲通撲通跪倒在電腦前。。) ps:以上為個人理解,有錯誤情指出=v=。。 代碼: 技術分享
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int fa[10001];
 4 struct dist{
 5     int u,v,dis;
 6 }a[3000001];
 7 int find(int x){
 8     if(fa[x]!=x) fa[x]=find(fa[x]);
 9     return fa[x];
10 }
11 void u(int
x,int y){ 12 if(find(x)!=find(y)) fa[find(x)]=find(y); 13 } 14 bool cmp(dist a,dist b){ 15 return a.dis<b.dis; 16 } 17 int main(){ 18 int n,m,k,p=0; 19 long long ans=0; 20 int c; 21 scanf("%d",&n); 22 m=(n+1)*n/2;//邊數 23 for(int i=1;i<=n;i++){ 24 for (int j=i;j<=n;j++){ 25 scanf("%d",&c); 26 p++; 27 a[p].u=i; a[p].v=j+1; a[p].dis=c; 28 }//建邊 29 } 30 sort(a+1,a+m+1,cmp); 31 n++; 32 for(int i=1;i<=n;i++) 33 fa[i]=i; 34 for(int i=1;i<=m;++i){ 35 if(find(a[i].u)!=find(a[i].v)){ 36 u(a[i].u,a[i].v); 37 k++; 38 ans+=a[i].dis; 39 } 40 if(k==n-1) break; 41 }//kruskal 42 printf("%lld\n",ans); 43 }
View Code

原諒我代碼寫的醜。。原諒我縮進寫的醜。。畢竟模板是從pascal翻譯過來的。。還學了一波多關鍵字快排。。

BZOJ 3714: [PA2014]Kuglarz