洛谷2986 2754

洛谷2986
  • 树状dp
  • d p [ i ] dp[i] dp[i] i i i为根时不方便程度
  • d p [ i ] = d p [ f a [ i ] ] − s u m s o n [ i ] ∗ w ( i , f a [ i ] ) + ( n − s u m s o n [ i ] ) ∗ w ( i , f a [ i ] ) dp[i]=dp[fa[i]]-sumson[i]*w(i,fa[i]) + (n-sumson[i])*w(i,fa[i]) dp[i]=dp[fa[i]]sumson[i]w(i,fa[i])+(nsumson[i])w(i,fa[i])
  • s u m s o n [ i ] sumson[i] sumson[i] i i i为根的子树所有结点奶牛总和, n n n所有结点奶牛总和
  • 爆搜求出 d p [ 1 ] dp[1] dp[1] ,跑树上dp 求出其余节点答案
LL dfs_1(int now,int fa)
{
    sum_son[now]=c[now];
    for(int i=head[now];i!=-1;i=edge[i].next)
    {
        int v=edge[i].t;
        if(v!=fa)
            sum_son[now]+=dfs_1(v,now);
    }
    return sum_son[now];
}
void dfs_2(int now,int fa,LL w)
{
    if(now!=1)
        dp[1]+=w*c[now];
    for(int i=head[now];i!=-1;i=edge[i].next)
    {
        int v=edge[i].t;
        LL ww=edge[i].l;
        if(v!=fa)
        {
            dfs_2(v,now,w+ww);
        }
    }
    return ;
}
void dfs_3(int now,int fa,LL w)
{
    if(now!=1)
        dp[now]=dp[fa]+(sum_o-2*sum_son[now])*(w);
    for(int i=head[now];i!=-1;i=edge[i].next)
    {
        int v=edge[i].t;
        LL ww=edge[i].l;
        if(v!=fa)
            dfs_3(v,now,ww);
    }
    return ;
}
void solve()
{
    LL ans=LINF;
    memset(head,-1,sizeof(head));
    for(int i=1;i<n;i++)
        add(F[i],T[i],L[i]),add(T[i],F[i],L[i]);
    for(int i=1;i<=n;i++)
        sum_o+=c[i];
    dfs_1(1,1);
    dfs_2(1,1,0);
    dfs_3(1,1,0);
    for(int i=1;i<=n;i++)
        ans=min(ans,dp[i]);
    cout<<ans<<endl;
    return ;
}
洛谷2754
  • 分层网络流
  • 以时间分层 k ∗ ( n + 2 ) + i k*(n+2)+i k(n+2)+i, 1 ≤ i ≤ n + 2 1 \leq i \leq n+2 1in+2分别为第k秒的,地球,n个空间站,月球。
  • i i i秒的地球和空间站分别向1秒后的自己建边容量无限,月球则反向建边
  • 按飞船每秒所在位置建边容量为飞船容量
  • 并查集检查是否有解
  • 每秒一建边跑dinic最大流大于k即为最优解
struct node
{
    int t,next;
    LL l;
} edge[N];
int tot,head[N],cur[N];
int dep[N];
int S,T;
void add(int f,int t,LL l)
{
    edge[tot].t=t;
    edge[tot].l=l;
    edge[tot].next=head[f];
    head[f]= tot++;
}

bool bfs(int now)  // ×î´óÁ÷
{
    memset(dep,0,sizeof(dep));
    dep[now]=1;
    queue<int> Q;
    Q.push(now);
    while(!Q.empty())
    {
        int u=Q.front();
        Q.pop();
        for(int i=head[u]; i!=-1; i=edge[i].next)
        {
            int v=edge[i].t;
            if(!dep[v]&&edge[i].l)
            {
//                cout<<"*"<<v<<" "<<dep[v]<<endl;
                dep[v]=dep[u]+1;
                Q.push(v);
                if(v==T)
                    return true;
            }
        }
    }
    return dep[T]!=0;
}

LL dfs(int now,LL flo)
{
    LL lop=flo;
    if(now==T)
        return flo;
    for(int i=cur[now]; i!=-1; i=edge[i].next)
    {
        cur[now]=edge[i].next;
        int v=edge[i].t;
        if(dep[v]==dep[now]+1&&edge[i].l)
        {
            LL p=dfs(v,min(lop,edge[i].l));
            lop-=p;
            edge[i].l-=p;
            edge[i^1].l+=p;
            if(!p)
                dep[v]=0;
            if(!lop)
                break;
        }
    }
    return flo-lop;
}

int n,m,k;
int h[210],r[210],SS[210][210];

int fa[N];

int fin(int x)
{
    if(fa[x]==x)
        return x;
    return fa[x]=fin(fa[x]);
}

void solve()
{
    LL ans=0;
    S=0,T=1000000;
    memset(head,-1,sizeof(head));
    for(int i=1; i<=n+2; i++)
        fa[i]=i;
    for(int i=1; i<=m; i++)
    {
        for(int j=2; j<=r[i]; j++)
        {
            int x=SS[i][j],y=SS[i][j-1];
            x=fin(x),y=fin(y);
            fa[x]=y;
        }
    }
    if(fin(1)!=fin(n+2))
    {
        cout<<"0"<<endl;
        return ;
    }
    add(n+2,T,INF),add(T,n+2,0);
    for(int i=1; i<=1000000; i++)
    {
        add(S,1+(i-1)*(n+2),INF),add(1+(i-1)*(n+2),S,0);//
        for(int j=1;j<=n+1;j++)
            add(j+(i-1)*(n+2),j+i*(n+2),INF),add(j+i*(n+2),j+(i-1)*(n+2),0);
        add(n+2+i*(n+2),n+2+(i-1)*(n+2),INF),add(n+2+(i-1)*(n+2),n+2+i*(n+2),0);
        for(int j=1;j<=m;j++)
        {
            int last=(i)%r[j];
            if(last==0)
                last=r[j];
            last=SS[j][last];
            last+=(i-1)*(n+2);
            int now=(i+1)%r[j];
            if(now==0)
                now=r[j];
            now=SS[j][now];
            now+=i*(n+2);
            add(last,now,h[j]),add(now,last,0);
        }
        while(bfs(S))
        {
            memcpy(cur,head,sizeof(head));
            ans+=dfs(S,INF);
        }
        if(ans>=k)
        {
            cout<<i<<endl;
            break;
        }
    }
    return ;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

    cin>>n>>m>>k;
    for(int i=1;i<=m;i++)
    {
        cin>>h[i]>>r[i];
        for(int j=1;j<=r[i];j++)
        {
            cin>>SS[i][j];
            if(SS[i][j]!=-1) SS[i][j]++;
            else SS[i][j]=n+2;
        }
    }
    solve();
    return 0;
}
/*
0 S

1 n+2 1s
n+2 +1   n+2 + n+2 2s

1e6 T
*/
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值