1. 程式人生 > >BZOJ 3714 PA2014 Kuglarz

BZOJ 3714 PA2014 Kuglarz

不存在 int 分享 inline 圖片 truct continue edge n+1

技術分享圖片

【題解】

  我們用sum[i]表示1~i的奇偶性,這樣,我們要知道每個點的情況就必須知道每一個sum[i].

  如果我們當前已知sum[i-1],我們就可以通過查詢i~j的情況知道sum[j],即查詢i~j的操作是sum[i-1]與sum[j]相互轉化的途徑。那麽我們可以把查詢操作當成一條連接i-1與j的邊,這條邊的邊權是查詢代價c[i][j]. 那麽我們跑一遍最小生成樹使得0~n這n+1個點互相聯通即可得到所有的sum. 因為計算sum[i]的值的過程可以用0號點到i號點的簡單路徑表示。即如果0到i的簡單路徑是0-->5-->6-->2,那麽sum[2]的計算過程就是已知sum[0],通過查詢0~5得到sum[5],再通過查詢5~6得到sum[6],最後通過查詢2~6得到sum[2].

  那麽為什麽這樣做就是代價最小的?即如果不求出每個點的sum,會不會存在比這種做法代價更小的查詢方式?答案是不存在。因為要知道每個點的情況,我們必須把原序列劃分成n個區間,也就是說我們最少要查詢n次,並且這n次的效果不能重疊,即如果查詢了1~5和1~3,我們一定不會查詢4~5。在最小生成樹中,我們也是選擇最小的n條邊使n+1個點聯通,因此這種做法就是最優做法。

#include<cstdio>
#include<algorithm>
#define N (2010)
using namespace std;
int n,m,fa[N],cnt;
long long ans=0;
struct edge{int u,v,dis;}e[N*N];
inline int read(){
	int k=0,f=1; char c=getchar();
	while(c<‘0‘||c>‘9‘)c==‘-‘&&(f=-1),c=getchar();
	while(‘0‘<=c&&c<=‘9‘)k=k*10+c-‘0‘,c=getchar();
	return k*f;
}
bool cmp(edge x,edge y){return x.dis<y.dis;}
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
int main(){
	n=read(); 
	for(int i=0;i<=n;i++) fa[i]=i;
	for(int i=1;i<=n;i++)
	for(int j=i;j<=n;j++){
		e[++m].u=i-1; e[m].v=j; e[m].dis=read();
	}
	sort(e+1,e+1+m,cmp);
	for(int i=1;i<=m;i++){
		int u=find(e[i].u),v=find(e[i].v);
		if(u==v) continue;
		ans+=e[i].dis; fa[u]=v; cnt++;
		if(cnt==n) break;
	}
	printf("%lld\n",ans);
	return 0;
}

  

  

BZOJ 3714 PA2014 Kuglarz