[BZOJ3714]&&[PA2014]Kuglarz

描述 Description

魔术师的桌子上有 n 个杯子排成一行,编号为 1,2,…,n,其中某些杯子底下藏有一个小球,如果你准确地猜出是哪些杯子,你就可以获得奖品。花费 c_ij 元,魔术师就会告诉你杯子 i,i+1,…,j 底下藏有球的总数的奇偶性。

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

输入格式 InputFormat

第一行一个整数 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 个数。

输出格式 OutputFormat

输出一个整数,表示最少花费。

样例输入 SampleInput

5
1 2 3 4 5
4 3 2 1
3 4 5
2 1
5

样例输出 SampleOutput

7

来源 Source

鸣谢 Jcvb


BZOJ 3714


代码 Code

给出 [i,j] 的奇偶性即为已知 sum[i-1]和 sum[j]的奇偶性(sum[]为前缀和),那么为了得出每个杯子下是否藏球即必须得到所有的前缀和,即所有点互相连通,即为求最小生成树。

#include <stdio.h>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;
int i,j,t,n,m,l,r,k,z,y,x;
struct edge
{
    int x,y,z;
    bool operator < (const edge& tmp) const
    {
        return (z!=tmp.z)?(z<tmp.z):((x!=tmp.x)?(x<tmp.x):(y<tmp.y));
    }
};
vector <edge> e;
int fa[2005];
long long ans;
int getfa(int s)
{
    if (fa[s]==s) return s;
    fa[s]=getfa(fa[s]);
    return fa[s];
}
int main()
{
    e.clear();
    scanf("%d",&n);
    for (i=1;i<=n;i++) fa[i]=i;
    for (i=1;i<=n;i++) for (j=i;j<=n;j++)
    {
        scanf("%d",&t);
        e.push_back((edge){i-1,j,t});
    }
    sort(e.begin(),e.end());
    ans=0;
    for (i=0;i<e.size();i++) if (getfa(e[i].x)!=getfa(e[i].y))
    {
        fa[getfa(e[i].x)]=e[i].y;
        ans+=e[i].z;
    }
    printf("%lld",ans);
    return 0;
}