• bzoj4593: [Shoi2015]聚变反应炉


    这道题的难点其实是在设DP方程,见过就应该会了

    令f0,i表示先激发i的父亲,再激发i,把i的整棵子树都激发的最小费用

    f1,i表示先激发i,再激发i的父亲,把i的整棵子树都激发的最小费用

    设x,y为i的孩子,先激发x再激发i再激发y有

    f0,i=∑(f1,y-cy)+∑f0,x+di-cfa

    f1,i=∑(f1,y-cy)+∑f0,x+di

    其中差的只有cfa,即0<=f1,i-f0,i<=1,对于typeA就容易做了,若两者相等就选f1,它可以消父亲,否则选f0,因为父亲消的次数有限,而即使消了也只是和选f0得到相同的结果

    对于TypeB做树上背包,Fi,j表示第i个点,孩子节点给它贡献了j的最小费用,更新f0,f1

    我码力太弱了。。在判断i是否已经被全部消完的时候f0和1要分开判。。。

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    using namespace std;
    
    struct node
    {
        int x,y,next;
    }a[210000];int len,last[110000];
    void ins(int x,int y)
    {
        len++;
        a[len].x=x;a[len].y=y;
        a[len].next=last[x];last[x]=len; 
    }
    
    int n,d[110000],c[110000]; bool type;
    int f[2][110000],F[2100][11000],li[2100],t[11000];
    void dfs(int x,int fr)
    {
        if(type==false)
        {
            f[0][x]=max(d[x]-c[fr],0);
            f[1][x]=d[x];
        }
        else F[x][0]=0;
        int sumc=0;
        for(int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            if(y!=fr)
            {
                dfs(y,x);sumc+=c[y];
                if(type==false)
                {
                    if(f[0][y]==f[1][y])
                    {
                        f[0][x]+=f[1][y]-c[y]*((d[x]-c[fr])>=c[y]);
                        f[1][x]+=f[1][y]-c[y]*(d[x]>=c[y]);
                        d[x]-=c[y];
                    }
                    else
                        f[0][x]+=f[0][y], f[1][x]+=f[0][y];
                }
                else
                {
                    memset(t,63,sizeof(t));
                    for(int i=min(sumc,li[x]);i>=0;i--)t[i]=F[x][i]+f[0][y];
                    for(int i=min(sumc,li[x]);i>=0;i--)
                    {
                        int u=min(sumc,i+c[y]);
                        if(i+c[y]>li[x])t[u]=min(t[u],F[x][i]+f[1][y]);
                        else t[u]=min(F[x][u]+f[0][y],F[x][i]+f[1][y]);
                    }
                    memcpy(F[x],t,sizeof(F[x]));
                    li[x]+=c[y];
                }
            }
        }
        if(type==true)
        {
            for(int i=min(sumc,li[x]);i>=0;i--)
            {
                f[0][x]=min(f[0][x],F[x][i]+max(d[x]-i-c[fr],0));
                f[1][x]=min(f[1][x],F[x][i]+max(d[x]-i,0));
            }
        }
    }
    
    int main()
    {
        freopen("a.in","r",stdin);
        freopen("a.out","w",stdout);
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%d",&d[i]);
        type=false;
        for(int i=1;i<=n;i++)
            scanf("%d",&c[i]),type|=(c[i]>1);
            
        int x,y;
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            ins(x,y),ins(y,x);
        }
        memset(f,63,sizeof(f));
        memset(F,63,sizeof(F));
        dfs(1,0);
        printf("%d
    ",f[1][1]);
        
        return 0;
    }
  • 相关阅读:
    产生随机不重复ID
    .NET 中使用 SQlite 数据库_1.新数据库的创建
    WCF 服务IIS部署 SvcUtil.exe 工具文件地址 及 生成代理类命令
    查看进程占用各字段含义
    内存溢出
    Python 正则表达式使用问题集锦
    Ninja编译过程分析
    git 命令使用集锦
    使用aapt查看当前apk的属性
    Android PowerManager电源管理(Android N )
  • 原文地址:https://www.cnblogs.com/AKCqhzdy/p/10250926.html
Copyright © 2020-2023  润新知