[BZOJ3714][PA2014]Kuglarz
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
1 2 3 4 5
4 3 2 1
3 4 5
2 1
5
Sample Output
7
这题太神了。
每次询问[L, R],相当于知道了sum[R] - sum[L-1]的奇偶性, 然后我们知道sum[0]。
把R向L-1连一条边权为C_ij的边,所以问题就转化成求0~n个点的最小生成树。
#include <iostream> #include <cstdio> #include <algorithm> #include <queue> #include <cstring> using namespace std; inline int read() { int res=0;char ch=getchar(); while(!isdigit(ch))ch=getchar(); while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar(); return res; } #define reg register #define INT long long int n; struct edge { int x, y, val; }ed[2005*2005]; bool cmp(edge a, edge b) { return a.val < b.val; } int cnt; inline void add(int x, int y, int z) { ed[++cnt] = (edge){x, y, z}; } int fa[2005]; int Find(int x) {return x==fa[x]?x:fa[x]=Find(fa[x]);} INT ans; int main() { n = read(); for (reg int i = 1 ; i <= n ; i ++) { for (reg int j = i ; j <= n ; j ++) { int x = read(); add(i - 1, j, x); } } sort(ed + 1, ed + 1 + cnt, cmp); for (reg int i = 0 ; i <= n ; i ++) fa[i] = i; int k = 0; for (reg int i = 1 ; i <= cnt ; i ++) { int x = ed[i].x, y = ed[i].y; int fx = Find(x), fy = Find(y); if (fx == fy) continue; fa[fx] = fy; k++; ans += ed[i].val; if (k == n) break; } printf("%lld\n", ans); return 0; }