首页 > 代码库 > BZOJ 3714: [PA2014]Kuglarz
BZOJ 3714: [PA2014]Kuglarz
呃。。好像弃坑了好久=v=。。本来打算在bzoj每刷10题合起来写一份题解。。但是1个月好像还刷不到10题的样子(水题除外),所以还是单独写一下题解。。
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
题目大意:自行理解。。
算法:前缀和+最小生成树+奇技淫巧?
看到这题立刻就想到可以把每个杯底下是否有球看成一个01状态。。然后想了一个用前缀和贪心的办法。。然而行不通。。
然后默默翻开了题解。。
看的一脸懵逼。。
最后看懂了。。
因为要知道所有情况,所以要将这个01序列通过前缀和分成n块,那么就是怎么分割的问题了。。
所以可以抽象成一个图,知道i到j奇偶性的代价就是i连到j的边权,因为前缀和有0,所以n+1个点,连成最小代价,那么就是求这n+1个点的最小生成树了。。
只需要在读入的时候连一下边,然后跑一遍kruskal就好辣.>v<(表示扑通扑通跪倒在电脑前。。)
ps:以上为个人理解,有错误情指出=v=。。
代码:
View Code
1 #include<bits/stdc++.h> 2 using namespace std; 3 int fa[10001]; 4 struct dist{ 5 int u,v,dis; 6 }a[3000001]; 7 int find(int x){ 8 if(fa[x]!=x) fa[x]=find(fa[x]); 9 return fa[x]; 10 } 11 void u(int x,int y){ 12 if(find(x)!=find(y)) fa[find(x)]=find(y); 13 } 14 bool cmp(dist a,dist b){ 15 return a.dis<b.dis; 16 } 17 int main(){ 18 int n,m,k,p=0; 19 long long ans=0; 20 int c; 21 scanf("%d",&n); 22 m=(n+1)*n/2;//边数 23 for(int i=1;i<=n;i++){ 24 for (int j=i;j<=n;j++){ 25 scanf("%d",&c); 26 p++; 27 a[p].u=i; a[p].v=j+1; a[p].dis=c; 28 }//建边 29 } 30 sort(a+1,a+m+1,cmp); 31 n++; 32 for(int i=1;i<=n;i++) 33 fa[i]=i; 34 for(int i=1;i<=m;++i){ 35 if(find(a[i].u)!=find(a[i].v)){ 36 u(a[i].u,a[i].v); 37 k++; 38 ans+=a[i].dis; 39 } 40 if(k==n-1) break; 41 }//kruskal 42 printf("%lld\n",ans); 43 }
原谅我代码写的丑。。原谅我缩进写的丑。。毕竟模板是从pascal翻译过来的。。还学了一波多关键字快排。。
BZOJ 3714: [PA2014]Kuglarz
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。