TYVJP1666城市建設
阿新 • • 發佈:2018-12-10
這題寫的不明不白的
應該是Kruskal
因為我也沒太搞懂咋做
當我在廢話就好了
我們對於兩個本來就有邊的城市,考慮先在哪個城市建房
對於兩個城市i,j,我們先在i建房的代價是,化簡一下,可以得到(某等差數列),然後在建j的代價是,化簡和上面一樣
先建j同理,然後我們發現,一個點後面那個**“某等差數列”**會被重複多次,所以我們先算前面的,後面的最後再加上,然後把兩種情況取min加到ans裡
對於沒有邊的城市,把上面的情況去掉等差數列,然後取min+兩邊還沒蓋房子時的人數和,當邊權去做最小生成樹
//By AcerMo
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lli long long int
using namespace std;
const int M=100;
lli n,m,ans;
char map[M][M];
lli st[M],ed[M],co[M];
int fa[M],siz[M],cnt=1,tot;
struct edge
{
lli fr,to,cos;
bool friend operator < (edge a,edge b)
{return a.cos<b.cos;}
}e[M*M];
inline int read()
{
int x=0;char ch=getchar();
while (ch>'9'||ch<'0') ch=getchar();
while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
inline int find(int x)
{
if (fa[x]!=x) return fa[x]=find(fa[x]);
return x;
}
inline void unionn(int x,int y)
{
if (siz[x]<=siz[y]) siz[y]+=siz[x],fa[x]=y;
else siz[x]+=siz[y],fa[y]=x;
return ;
}
inline lli calc(int i,int k)
{
return co[i]*(ed[i]-st[i])*st[k]+co[k]*(ed[k]-st[k])*ed[i];
}
inline void Kru()
{
for (int i=1;i<=tot&&cnt<n;i++)
{
int r1=find(e[i].fr);
int r2=find(e[i].to);
if (r1!=r2)
cnt++,ans+=e[i].cos,unionn(r1,r2);
}
return ;
}
signed main()
{
n=read();
for (int i=1;i<=n;i++) st[i]=read();
for (int i=1;i<=n;i++) ed[i]=read();
for (int i=1;i<=n;i++) co[i]=read();
for (int i=1;i<=n;i++) fa[i]=i,siz[i]=1;
for (int i=1;i<=n;i++) scanf("%s",map[i]+1);
for (int i=1;i<=n;i++)
for (int k=1;k<=n;k++)
if (k>i)
{
if (map[i][k]=='Y')
{
int r1=find(i),r2=find(k);
if (r1!=r2) cnt++,unionn(r1,r2);
ans+=min(calc(i,k),calc(k,i));
}
else
{
e[++tot].fr=i;e[tot].to=k;
e[tot].cos=min(calc(i,k),calc(k,i));
}
}
m=read();
for (int i=1;i<=tot;i++)
e[i].cos+=m*(st[e[i].fr]+st[e[i].to]);
sort(e+1,e+tot+1);Kru();
for (int i=1;i<=n;i++)
ans+=(st[i]-1+ed[i])*(ed[i]-st[i])/2*co[i];
cout<<ans;
return 0;
}