最小生成树一般都比较考验思维啊。。
题面:
魔术师的桌子上有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)的完全图,做最小生成树就好了。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#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; }