[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

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;
}

 

posted @ 2018-08-19 21:07  zZhBr  阅读(159)  评论(0编辑  收藏  举报