BZOJ3714 [PA2014]Kuglarz -最小生成树

最小生成树一般都比较考验思维啊。。

题面:

魔术师的桌子上有n个杯子排成一行,编号为1,2,…,n,其中某些杯子底下藏有一个小球,如果你准确地猜出是哪些杯子,你就可以获得奖品。

花费Ci,j元,魔术师就会告诉你杯子i,i+1,…,j底下藏有球的总数的奇偶性。 

采取最优的询问策略,你至少需要花费多少元,才能保证猜出哪些杯子底下藏着球?  n<=5000

第一眼似乎看不出什么,好像并不好做。

我们来从条件入手,给定的是一段[l,r]的奇偶性。

那么我们注意到,如果知道了[1,l-1]或[1,r]中任意一个的奇偶性,另一个的就知道了。

可以发现这是一个类似前缀和的东西,我们先定义为s[i],表示前i个的奇偶性

那么问题即求s[1]~s[n]。

那么根据上面提到的性质,我们就相当于建一个n+1个点(包括0)的完全图,做最小生成树就好了。

#include <bits/stdc++.h>
using namespace std;
inline int gi () {
    int x=0, w=0; char ch=0;
    while (! (ch>='0' && ch<='9') ) {
    if (ch=='-') w=1;
    ch=getchar ();
    }
    while (ch>='0' && ch<='9') {
    x= (x<<3) + (x<<1) + (ch^48);
    ch=getchar ();
    }
    return w?-x:x;
}

const int N=2018;
long long Ans;
int n,tot,fa[N];

int Get_fa (int x) {
    return x==fa[x]?x:fa[x]=Get_fa (fa[x]);
}

struct Edge {
    int x, y, ver;
}e[N*N];
bool cmp (Edge a, Edge b) {
    return a.ver<b.ver;
}

int main ()
{
    n=gi ();
    for (int i=1;i<=n;++i) 
    for (int j=i;j<=n;++j) {
        e[++tot].x=i-1, 
        e[tot].y=j, e[tot].ver=gi ();
    }
    sort (e+1, e+tot+1, cmp);
    for (int i=1;i<=n;++i)
    fa[i]=i;
    for (int i=1;i<=tot;++i) {
    int fax, fay;
    fax=Get_fa (e[i].x), fay=Get_fa (e[i].y);
    if (fax==fay) continue;
    fa[fax]=fay;
    Ans+=e[i].ver;
    }
    printf  ("%lld\n", Ans);    
    return 0;
}
BY BHLLX

 

posted @ 2018-11-08 15:59  薄荷凉了夏  阅读(172)  评论(0编辑  收藏  举报