zoukankan      html  css  js  c++  java
  • GKurumi记

    20191008陈蒟蒻爆0记

    T2、City

    by GKurumi

    题目描述:(加密)

    这个题一开始看起来冗杂,之后我们考虑一下,边的话基本可以处理成一个定值,因为没有边的城市建边一定是最少人的时候建边人数最少。

    之后思考一个结论,假设有城市x,y对应bx,by,hx,hy需要在这两个城市各建若干个房子,那么我们一个一个城市分别完成一定比交错完成优。

    证明先建大的最优:

    假设hx>hy,那么先在x建应比在y建优,如果每一个城市都只要建两所房子的话:
    
    hx(bx+by)+hy(bx+by+1)+hx(bx+by+2)+hy(bx+by+3)
    
    hx(bx+by)+hx(bx+by+1)+hy(bx+by+2)+hy(bx+by+3)
    
    约掉同类项:
    
    有(2hy+hx)−(hy+2hx)=hy−hx<0成立。
    
    需要建两个房子以上的时候可以归纳。
    

    之后我们用最小生成树

    计算边权的时候如果有边:(h[x] imes b[y] imes (a[x]-b[x]))

    如果没有边是,需在基础上加上修路钱:(R imes(b[x]+b[y]))

    建好之后就可以跑最小生成树了。

    最后要注意最小生成树算完还差点火候,就是在最后,因为对于每一个点x,

    它对答案的贡献是:hx(bx+(bx+1)+(bx+2)+...+(ax−1))+hx∗(sum(y))hx(bx+(bx+1)+(bx+2)+...+(ax−1))+hx∗by∗(ax-bx)

    y是x能直接联通的点。所以我们需要在处理处理一个等差数列相加。

    就完美了。

    上代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch-'0');ch=getchar();}
    	return x*f;
    }
    int n,fa[10005],a[10005],b[10005],h[100005],R,mp[1005][1005],ans,ecnt;
    
    struct node
    {
    	int u,v;
    	long long val;
    }e[2505];
    int cnt;
    void add(int u,int v,int val)
    {
    	e[++cnt].u=u;
    	e[cnt].v=v;
    	e[cnt].val=val;
    }
    bool cmp(node a,node b)
    {
    	return a.val<b.val;
    }
    
    int find(int x)
    {
    	if(fa[x]==x)return x;
    	return fa[x]=find(fa[x]);
    }
    
    signed main()
    {
    //	freopen("city.in","r",stdin);
    //	freopen("city.out","w",stdout);
    	n=read();
    	for(int i=1;i<=n;i++) fa[i]=i; 
    	for(int i=1;i<=n;i++) b[i]=read();
    	for(int i=1;i<=n;i++) a[i]=read();
    	for(int i=1;i<=n;i++) h[i]=read();
    	char st[10005];
    	for(int i=1;i<=n;i++)
    	{
    		
    		cin>>st+1;
    		for(int j=1;j<=n;j++)
    		{
    			if(st[j]=='N')
    			{
    				mp[i][j]=0;
    			}
    			else mp[i][j]=1;
    		}
    	}
    	R=read();
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=1;j<i;j++)
    		{
    			if(mp[i][j])
    			{
    				if(h[i]<h[j])//先算hj 
    				{
    					ans+=h[j]*b[i]*(a[j]-b[j])+h[i]*a[j]*(a[i]-b[i]);
    				}
    				else
    				{
    					ans+=h[i]*b[j]*(a[i]-b[i])+h[j]*a[i]*(a[j]-b[j]);
    				}
    				int x=find(i),y=find(j);
    				if(x==y)continue;
    				fa[x]=y;
    				++ecnt;
    			}
    			else
    			{
    				if(h[i]<h[j])
    				{
    					add(i,j,((h[j]*b[i]*(a[j]-b[j])+h[i]*a[j]*(a[i]-b[i]))+R*(b[i]+b[j])));
    				}
    				else
    				{
    					add(i,j,((h[i]*b[j]*(a[i]-b[i])+h[j]*a[i]*(a[j]-b[j]))+R*(b[i]+b[j])));
    				}
    			}
    		}
    	}
    	sort(e+1,e+1+cnt,cmp);
    	for(int i=1;i<=cnt&&ecnt<n-1;i++)
    	{
    		int u=find(e[i].u),v=find(e[i].v);
    		if(u==v)continue;
    		fa[u]=v;
    		ans+=e[i].val;
    		++ecnt;
    	}
    	for(int i=1;i<=n;i++)
    	{
    		ans+=h[i]*(a[i]-b[i])*(b[i]+a[i]-1)/2;
    	}
    	cout<<ans;
    	return 0;
    }
    /*
    4
    1 1 1 1
    1 3 1 2
    8 5 3 2
    NYNN
    YNYN
    NYNY
    NNYN
    100000
    */		
    

    如有转载,请标明原地址出处,原地址链接

  • 相关阅读:
    HDU 3586 Information Disturbing (树形DP+二分)
    HDU 6053 TrickGCD (莫比乌斯函数)
    51Nod 1554 欧姆诺姆和项链 (KMP)
    HDU 6153 A Secret (KMP)
    HDU 6156 Palindrome Function (数位DP)
    HDU 6148 Valley Numer (数位DP)
    UVa 1513 Movie collection (树状数组)
    HDU 6125 Free from square (状压DP+背包)
    UVa 10766 Organising the Organisation (生成树计数)
    tensorflow 待阅读的资料
  • 原文地址:https://www.cnblogs.com/GKurumi/p/11636150.html
Copyright © 2011-2022 走看看