首页 > 代码库 > bzoj3714 [PA2014]Kuglarz
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
HINT
把杯子根据有没有球看成0/1的序列,题意是可以询问一段区间的和,要求确定每一个点的状态数
显然要一直取到长度为1的区间,才能确定这个点。
考虑把原来的序列划分成一些连续的区间,只要求出每一段的最小代价加上这样划分的代价就好了
这样变成不停的在序列上划分。显然每次划分都使得区间数+1,最终必须划分成n个长度为1的区间,因为要知道每一个点的状态
这样一来只需要考虑划分成n-1个区间的最小代价就好了
但是实际上划分的顺序对答案是不影响的,而且显然划分成n-1个区间就相当于连n-1条线
所以变成最小生成树了……真神奇
另外……因为a[i][j]实际上是把区间[i-1,j]提出来的代价,所以应该求0到n一共n+1个点的最小生成树
听说prim加个堆优化能跑得飞快,但是还没打,就写了个很sb的n^2prim
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdlib> 5 #include<algorithm> 6 #include<cmath> 7 #include<queue> 8 #include<deque> 9 #include<set>10 #include<map>11 #include<ctime>12 #define LL long long13 #define inf 214748364714 #define pa pair<int,int>15 #define pi 3.141592653589793238462643383279502884197116 #define N 201017 using namespace std;18 int a[N][N];19 int near[N];20 bool mrk[N];21 int n;22 LL ans;23 inline LL read()24 {25 LL x=0,f=1;char ch=getchar();26 while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}27 while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}28 return x*f;29 }30 inline void prim()31 {32 mrk[0]=1;33 for(int i=1;i<=n;i++)34 near[i]=a[0][i];35 for (int i=1;i<=n;i++)36 {37 int mn=inf,fnd=0;38 for (int j=1;j<=n;j++)39 if (!mrk[j]&&near[j]<mn)40 {41 mn=near[j];42 fnd=j;43 }44 ans+=mn;45 mrk[fnd]=1;46 for (int j=1;j<=n;j++)47 if (!mrk[j]) near[j]=min(near[j],a[fnd][j]);48 }49 }50 int main()51 {52 n=read();53 for (int i=1;i<=n;i++)54 for (int j=i;j<=n;j++)55 a[i-1][j]=a[j][i-1]=read();56 prim();57 printf("%lld\n",ans);58 }
bzoj3714 [PA2014]Kuglarz
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。