TYVJP1666城市建设

版权声明:我这么弱的蒟蒻,虽然博文不是很好,但也请标明转发地址喵! https://blog.csdn.net/ACerAndAKer/article/details/82756012

这题写的不明不白的

应该是Kruskal

因为我也没太搞懂咋做

当我在废话就好了

我们对于两个本来就有边的城市,考虑先在哪个城市建房
对于两个城市i,j,我们先在i建房的代价是 h [ i ] ( s t [ i ] + s t [ j ] ) + h [ i ] ( s t [ i ] + 1 + s t [ j ] ) + . . . + h [ i ] ( s t [ i ] + e d [ i ] s t [ i ] + s t [ j ] ) h[i]*(st[i]+st[j])+h[i]*(st[i]+1+st[j])+...+h[i]*(st[i]+ed[i]-st[i]+st[j]) ,化简一下,可以得到 h [ i ] ( e d [ i ] s t [ i ] ) s t [ j ] + h[i]*(ed[i]-st[i])*st[j]+ (某等差数列),然后在建j的代价是 h [ j ] ( s t [ j ] + e d [ i ] ) + h [ j ] ( s t [ j ] + 1 + e d [ i ] ) + . . . + h [ j ] ( s t [ j ] + e d [ j ] s t [ j ] ) h[j]*(st[j]+ed[i])+h[j]*(st[j]+1+ed[i])+...+h[j]*(st[j]+ed[j]-st[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;
}

猜你喜欢

转载自blog.csdn.net/ACerAndAKer/article/details/82756012
今日推荐