T1,T3不提。
T2城市建设,注意:
1.城市建造顺序按h从大到小排序,顺序与边无关;
2.i,j之间连边的代价为:(h[i]>h[j]) (b[i]+b[j])*r+(a[i]-b[i])*b[j]*h[i]+(a[j]-b[j])*a[i]*h[j];
3.赋好边权后跑最小生成树
错误代码如下:

#include<iostream> #include<cstdio> #include<algorithm> using namespace std; int n,ct,head[55],sid[55][55],r,fa[55],ep[3100]; long long ans; char dc; struct N{ int hd,to,next,w; }edge[3100]; struct C{ int b,a,h,pos; }p[55]; bool cmp(C x,C y) { return x.h>y.h; } bool cmp2(int x,int y) { return edge[x].w<edge[y].w; } int find(int x) { if(fa[x]==x)return x; return fa[x]=find(fa[x]); } void add(int x,int y,long long w) { ct++; edge[ct].hd=x; edge[ct].to=y; edge[ct].w=w; edge[ct].next=head[x]; head[x]=ct; } long long cl(int i) { long long tot=0; for(int k=0;k<p[i].a-p[i].b;k++) tot+=p[i].h*(p[i].b+k); return tot; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&p[i].b),fa[i]=i,p[i].pos=i;//存p的位置 for(int i=1;i<=n;i++) scanf("%d",&p[i].a); for(int i=1;i<=n;i++) scanf("%d ",&p[i].h); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { scanf("%c",&dc); if(dc==‘Y‘) { sid[i][j]=1;//i和j有直接相连的边 fa[i]=find(j); } if(j==n)scanf("%c",&dc); } scanf("%d",&r); for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++)// { if(find(i)!=find(j)) { int u,v; if(p[i].h>p[j].h)u=i,v=j;//先建造u的房子 else u=j,v=i; long long tot=0; tot+=p[u].h*(p[u].a-p[u].b)*p[v].b;//边权 tot+=p[v].h*(p[v].a-p[v].b)*p[u].a; tot+=r*(p[u].b+p[v].b); add(u,v,tot); } } for(int i=1;i<=ct;i++)ep[i]=i; sort(ep+1,ep+ct+1,cmp2);//ep记录edge的角标,将ep排序 for(int i=1;i<=ct;i++)//Kruskal { int u=edge[ep[i]].hd; int v=edge[ep[i]].to; if(find(u)!=find(v)) { fa[find(u)]=find(v); sid[u][v]=1;//有直接相连的边 sid[v][u]=1; ans+=r*(p[u].b+p[v].b);//ans加上连边的代价 } } sort(p+1,p+n+1,cmp);//按h排序 for(int i=1;i<=n;i++) { long long tot=0; for(int j=1;j<=n;j++) { if(!sid[p[i].pos][p[j].pos])continue; tot+=p[i].h*p[j].b*(p[i].a-p[i].b);//总代价加上连向此点的代价 } tot+=cl(i);//自己本身建造房子的代价 p[i].b=p[i].a;//之后用此点的b改变 ans+=tot; } printf("%lld",ans); return 0; }
正确代码如下:
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; int n,ct,fa[60]; long long ans,r; char dc; struct N{ int hd,to,next; long long w; }edge[3800]; struct C{ long long b,a,h; }p[60]; bool cmp(N x,N y) { return x.w<y.w; } int find(int x) { if(fa[x]==x)return x; return fa[x]=find(fa[x]); } void add(int x,int y,long long w) { ct++; edge[ct].hd=x; edge[ct].to=y; edge[ct].w=w; } long long cl(int i) { return p[i].h*(p[i].a+p[i].b-1)*(p[i].a-p[i].b)/2; } int main() { freopen("tree.in","r",stdin); freopen("tree.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%lld",&p[i].b),fa[i]=i; for(int i=1;i<=n;i++) scanf("%lld",&p[i].a); for(int i=1;i<=n;i++) scanf("%lld ",&p[i].h),ans+=cl(i); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { scanf("%c",&dc); if(i<j&&dc==‘Y‘) { ans+=min(p[i].h*p[j].b*(p[i].a-p[i].b)+p[j].h*p[i].a*(p[j].a-p[j].b), p[j].h*p[i].b*(p[j].a-p[j].b)+p[i].h*p[j].a*(p[i].a-p[i].b)); fa[find(i)]=find(j);//不能写fa[i]=find(j)! } if(j==n)scanf("%c",&dc); } scanf("%lld",&r); for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++)// { if(find(i)!=find(j)) { long long tot=0; tot+=min(p[i].h*p[j].b*(p[i].a-p[i].b)+p[j].h*p[i].a*(p[j].a-p[j].b), p[j].h*p[i].b*(p[j].a-p[j].b)+p[i].h*p[j].a*(p[i].a-p[i].b)); tot+=r*(p[i].b+p[j].b); add(i,j,tot); } } sort(edge+1,edge+ct+1,cmp); for(int i=1;i<=ct;i++) { int u=edge[i].hd; int v=edge[i].to; if(find(u)!=find(v)) { ans+=edge[i].w; fa[find(u)]=find(v); } } printf("%lld",ans); return 0; }