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]\times b[y]\times (a[x]-b[x])\)
如果没有边是,需在基础上加上修路钱:\(R\times(b[x]+b[y])\)
建好之后就可以跑最小生成树了。
上代码:
#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 */