zoukankan      html  css  js  c++  java
  • BZOJ 3714 PA2014 Kuglarz

    【题解】

      我们用sum[i]表示1~i的奇偶性,这样,我们要知道每个点的情况就必须知道每一个sum[i].

      如果我们当前已知sum[i-1],我们就可以通过查询i~j的情况知道sum[j],即查询i~j的操作是sum[i-1]与sum[j]相互转化的途径。那么我们可以把查询操作当成一条连接i-1与j的边,这条边的边权是查询代价c[i][j].  那么我们跑一遍最小生成树使得0~n这n+1个点互相联通即可得到所有的sum. 因为计算sum[i]的值的过程可以用0号点到i号点的简单路径表示。即如果0到i的简单路径是0-->5-->6-->2,那么sum[2]的计算过程就是已知sum[0],通过查询0~5得到sum[5],再通过查询5~6得到sum[6],最后通过查询2~6得到sum[2].

      那么为什么这样做就是代价最小的?即如果不求出每个点的sum,会不会存在比这种做法代价更小的查询方式?答案是不存在。因为要知道每个点的情况,我们必须把原序列划分成n个区间,也就是说我们最少要查询n次,并且这n次的效果不能重叠,即如果查询了1~5和1~3,我们一定不会查询4~5。在最小生成树中,我们也是选择最小的n条边使n+1个点联通,因此这种做法就是最优做法。而其实求每个点的sum是求每个点的奇偶性的充分必要条件,即两者是等价的,代价最小的查询方案是相同的。

    #include<cstdio>
    #include<algorithm>
    #define N (2010)
    using namespace std;
    int n,m,fa[N],cnt;
    long long ans=0;
    struct edge{int u,v,dis;}e[N*N];
    inline int read(){
    	int k=0,f=1; char c=getchar();
    	while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar();
    	while('0'<=c&&c<='9')k=k*10+c-'0',c=getchar();
    	return k*f;
    }
    bool cmp(edge x,edge y){return x.dis<y.dis;}
    int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
    int main(){
    	n=read(); 
    	for(int i=0;i<=n;i++) fa[i]=i;
    	for(int i=1;i<=n;i++)
    	for(int j=i;j<=n;j++){
    		e[++m].u=i-1; e[m].v=j; e[m].dis=read();
    	}
    	sort(e+1,e+1+m,cmp);
    	for(int i=1;i<=m;i++){
    		int u=find(e[i].u),v=find(e[i].v);
    		if(u==v) continue;
    		ans+=e[i].dis; fa[u]=v; cnt++;
    		if(cnt==n) break;
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    

      

      

  • 相关阅读:
    TextView文字排版问题:
    Cent OS 6 主机名设置
    windows server 时间同步
    DELL服务器SAS 5 I_R 完全配置手册
    SAS 5/iR Adapter 驱动下载
    U盘加载硬盘控制卡驱动安装Windows 2003 指南
    邮件客户端导入邮件通讯录地址薄
    Symantec System Recovery
    windows server 备份与还原
    Acronis 备份使用
  • 原文地址:https://www.cnblogs.com/DriverLao/p/8386967.html
Copyright © 2011-2022 走看看