[BZOJ 3714] [PA2014]Kuglarz

BZOJ传送门

题目描述

魔术师的桌子上有 n n n个杯子排成一行,编号为 1 , 2 , … , n 1,2,…,n 1,2,,n,其中某些杯子底下藏有一个小球,如果你准确地猜出是哪些杯子,你就可以获得奖品。花费 c i j c_{ij} cij元,魔术师就会告诉你杯子 i , i + 1 , … , j i,i+1,…,j i,i+1,,j底下藏有球的总数的奇偶性。
采取最优的询问策略,你至少需要花费多少元,才能保证猜出哪些杯子底下藏着球?

输入输出格式

输入格式

第一行一个整数 n ( 1 ≤ n ≤ 2000 ) n(1\le n\le 2000) n(1n2000)
i + 1 i+1 i+1 ( 1 ≤ i ≤ n ) (1\le i\le n) (1in) n + 1 − i n+1-i n+1i个整数,表示每一种询问所需的花费。其中 c i j c_{ij} cij(对区间 [ i , j ] [i,j] [i,j]进行询问的费用, 1 ≤ i ≤ j ≤ n , 1 ≤ c i j ≤ 1 0 9 1\le i\le j\le n,1\le c_{ij}\le 10^9 1ijn,1cij109)为第 i + 1 i+1 i+1行第 j + 1 − i j+1-i j+1i个数。

输出格式

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

输入输出样例

输入样例#1:
5
1 2 3 4 5
4 3 2 1
3 4 5
2 1
5
输出样例#1:
7

解题分析

真是一道神题…

我们注意到, 如果我们能以某种方式得到 [ a , b ] [a,b] [a,b] [ b + 1 , c ] [b+1,c] [b+1,c](可以通过已知的相加减), 那我们肯定不会再去查询 [ a , c ] [a,c] [a,c]。我们将每个杯子看做一个点, 这就等价于我们选取了 a − 1 → b a-1\to b a1b b → c b\to c bc的两条链, 并且在整个图中不会出现环。

这就是个 n + 1 n+1 n+1个点的最小生成树, 连边跑就好了。这里边有 O ( N 2 ) O(N^2) O(N2)条, 用 p r i m prim prim更好。

总复杂度 O ( N 2 ) O(N^2) O(N2)

代码如下:

#include <cstdio>
#include <cctype>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <climits>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 2050
template <class T>
IN void in(T &x)
{
	x = 0; R char c = gc;
	for (; !isdigit(c); c = gc);
	for (;  isdigit(c); c = gc)
	x = (x << 1) + (x << 3) + c - 48;
}
int dis[MX];
bool vis[MX];
int mp[MX][MX];
int dot, nex, d;
long long ans;
void prim()
{
	vis[0] = true;
	for (R int i = 1; i <= dot; ++i) dis[i] = mp[0][i];
	for (R int j = 1; j <= dot; ++j)
	{
		nex = 0, d = INT_MAX;
		for (R int i = 1; i <= dot; ++i) if(dis[i] < d && !vis[i]) d = dis[i], nex = i;
		vis[nex] = true; ans += dis[nex];
		for (R int i = 1; i <= dot; ++i) dis[i] = std::min(dis[i], mp[nex][i]);
	}
}
int main(void)
{
	in(dot);
	for (R int i = 1; i <= dot; ++i)
	for (R int j = i; j <= dot; ++j)
	in(mp[i - 1][j]), mp[j][i - 1] = mp[i - 1][j];
	for (R int i = 0; i <= dot; ++i) mp[i][i] = INT_MAX;
	prim();
	printf("%lld", ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值