bzoj3714: [PA2014]Kuglarz

来源:互联网 发布:d3.v4.min.js下载 编辑:程序博客网 时间:2024/05/17 13:42

链接

  http://www.lydsy.com/JudgeOnline/problem.php?id=3714

题解

  这题思路很神奇。
  要知道每一个数,可以从前缀和的角度考虑。
  如果知道了所有的前缀和,就一定能知道所有的数了,而且这两个问题一定是完全等价的,费用肯定也是一样的。
  异或是可以前缀和的,考虑一个操作cij,显然就是告诉了你si1sj的大小关系。有了这条关系之后,以后只要知道其中一个值,另一个就出来了,因此我们在图中建一条边eij,权值就是cij
  显然一开始唯一知道的就是s0,那你要做的工作就是花最小的费用使所有点和0这个点连通。
  

MST

代码

//最小生成树#include <cstdio>#include <algorithm>#define maxn 2017#define ll long longusing namespace std;int u[maxn*maxn], v[maxn*maxn], w[maxn*maxn], tot, f[maxn], num[maxn*maxn], N;ll cost;int find(int x){return x==f[x]?x:f[x]=find(f[x]);}void merge(int a, int b){f[find(a)]=find(b);}bool cmp(int a, int b){return w[a]<w[b];}void kruskal(){    int i;    for(i=1;i<=tot;i++)num[i]=i;    for(i=1;i<=N;i++)f[i]=i;    sort(num+1,num+tot+1,cmp);    for(i=1;i<=tot;i++)        if(find(u[num[i]])^find(v[num[i]]))merge(u[num[i]],v[num[i]]),cost+=w[num[i]];}int main(){    int x, i, j;    scanf("%d",&N);    for(i=1;i<=N;i++)for(j=i;j<=N;j++)u[++tot]=i-1, v[tot]=j, scanf("%d",w+tot);    kruskal();    printf("%lld",cost);    return 0;}
0 0