zoukankan      html  css  js  c++  java
  • [JSOI2008]魔兽地图DotR 做题心得

    [JSOI2008]魔兽地图DotR 做题心得

    马上要 JSOI2021 了,来看看以往的题

    对于树形dp题,就是要想一下:基本策略是什么?然后根据基本策略,想一想dp要维护什么,怎么转移。再加上一些套路之类的东西,维护一下。像本题用到的就是树上背包。

    还有就是,像树上花费多少价格购买甚么东西使得获利最大,长成这样的题,一般都是树上背包搞一搞。

    题解

    一些记号

    (n,m) 是物品数与总钱数

    我们定义 (pow(u)) 表示 (u) 的力量值,(pri(u)) 表示 (u) 的花费,(lim(u)) 表示 (u) 最多能搞多少个。

    对于非基础装备,(pri,lim) 并不是直接给,但是我们可以在树上算一下:

    (pri(u)) 就是它所需要的每个物品的价格乘以合成需要多少个物品,即

    [sumlimits_{vin son(u)} need(v)*pri(v) ]

    (lim(u)) 就是每个需要的物品的 (lim/need)(min),最后再和 (m/pri(u))(m) 是总钱数)取一下 (min)

    然后还有一些 dp 数组,后面再说

    基本策略与dp设状态

    我们肯定是,先买一堆基础物品,然后不断合上去

    对于中间的某些物品,我们用一部分增加力量值,并用剩下的一部分用来合成更高级的东西。注意我们并不一定全部用来合成,或者全部用来增加力量值。

    然后贯穿全题的,还有一个重要的东西:钱。钱是一切的根源,但是我们的钱有限,最重点要规划的就是钱怎么用。

    于是我们的dp就成型了:(f(u,j,k)) 表示 dp 到树上的点 (u),留 (j) 个传上去用来合成,现在花了 (k) 块钱,最大能获取的力量值。

    dp转移

    这个状态简单想一下大概是能转移的,考虑一下 (f(u,j,k)) 怎么转移

    我们枚举一共准备造 (J) 个 ((Jge j)),显然自己这里合成不需要花钱,所以钱((k) 块钱)全部花给儿子,假设这部分能获得的最大的力量值是 (P_{son})。然后贡献的力量值就是 (P_{son}+(J-j)*pow(u))

    (后面 (J-j) 是因为要留 (j) 个上传)

    现在的问题是 (P_{son}) 怎么算。假设每个儿子的 (f) 我们都能算出来,其实这就是一个合并背包的问题了,另开一个 dp 数组 (g) 来搞定这个问题。

    注:"背包合并"是我瞎口胡的一个说法,说着玩的,不知道它是否是一个专业的说法。

    (g[t][k]) 表示,考虑前 (t) 个儿子,花了 (k) 块钱,最大力量值。假设第 (t) 个儿子是 (v),那么 (v) 的义务是:上传 (j*need(v)) 个来给 (u) ,用来合成 (j)(u)。而它享有的权利是,获得 (k) 块钱中的一部分。

    于是我们枚举一下 (k) 块钱中分多少给它,得转移:

    [g[t][k]=g[t-1][k']+f(v,j*need(v),k-k') ]

    然后假设 (u) 的儿子总数为 (T),显然 (P_{son}) 就是 (g[T][k])

    到最后求完 (f) 之后,你会发现其实原树不连通,对于每个根都要求一遍,然后还要合并一下。

    但是其实这里的转移和 (g) 就几乎没区别了,除了没有责任义务的限制。抄着写,改改就行了。也是一个背包合并。

    总结

    有一个重要的思想是,我们固然要考虑当前怎么决策,但是也要为以后的决策做考虑:后面的决策需要用到哪些信息?要不要传上去?用什么方式传过去?这里联动一下 CF461E,也有类似的 “为后面的决策考虑” 的思想,只不过那个题传的信息过于简单了(

    我们联合!

    另一个重要的思想是,我们面对的问题和当前的局势非常的复杂,但是其实这个“局势”,只有少量的“特征值”,是我们关心的,而这就是我们的 (dp) 状态。比如我们虽然面临着复杂的分钱问题,但我们关心的只有:当前在哪,有多少钱,给上面多少。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    namespace Flandre_Scarlet
    {
        #define N 102
        #define M 2003
        #define F(i,l,r) for(int i=l;i<=r;++i)
        #define D(i,r,l) for(int i=r;i>=l;--i)
        #define Fs(i,l,r,c) for(int i=l;i<=r;c)
        #define Ds(i,r,l,c) for(int i=r;i>=l;c)
        #define MEM(x,a) memset(x,a,sizeof(x))
        #define FK(x) MEM(x,0)
        #define Tra(i,u) for(int i=G.st(u),v=G.to(i);~i;i=G.nx(i),v=G.to(i))
        #define p_b push_back
        #define sz(a) ((int)a.size())
        #define all(a) a.begin(),a.end()
        #define iter(a,p) (a.begin()+p)
        #define PUT(a,n) F(i,1,n) printf("%d ",a[i]); puts("");
        int I() {char c=getchar(); int x=0; int f=1; while(c<'0' or c>'9') f=(c=='-')?-1:1,c=getchar(); while(c>='0' and c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return ((f==1)?x:-x);}
        template <typename T> void Rd(T& arg){arg=I();}
        template <typename T,typename...Types> void Rd(T& arg,Types&...args){arg=I(); Rd(args...);}
        void RA(int *p,int n) {F(i,1,n) *p=I(),++p;}
        class Graph
        {
        public:
            struct edge{int v,w,nx;} e[N<<1];
            int head[N]; int ecnt=-1;
            void clear() {MEM(e,-1); MEM(head,-1); ecnt=-1;}
            void add(int u,int v,int w)
            {
                e[++ecnt]=(edge){v,w,head[u]}; head[u]=ecnt;
            }
            void add2(int u,int v,int w)
            {
                add(u,v,w),add(v,u,w);
            }
            int& st(int u) {return head[u];}
            int& to(int i) {return e[i].v;}
            int& nx(int i) {return e[i].nx;}
            int& need(int i) {return e[i].w;}
        }G;
        int n,m;
        bool type[N]; // 低级:0; 高级:1
        int fa[N];
        int power[N],price[N],lim[N];
        void Input()
        {
            Rd(n,m); 
            G.clear(); MEM(fa,-1);
            F(i,1,n)
            {
                power[i]=I();
                char o[3]; scanf("%s",o);
                if (o[0]=='A')
                {
                    type[i]=1;
                    int tot=I();
                    F(j,1,tot)
                    {
                        int v,need; Rd(v,need);
                        G.add(i,v,need); fa[v]=i;
                    }
                }
                else
                {
                    type[i]=0;
                    Rd(price[i],lim[i]);
                }
            }
        }
        int f[N][N][M],g[N][M];
        void DFS(int u)
        {
            if (!type[u])
            {
                lim[u]=min(lim[u],m/price[u]);
                F(J,0,lim[u]) F(j,0,J)
                {
                    f[u][j][J*price[u]]=(J-j)*power[u];
                } 
                return;
            }
            lim[u]=1145141919;
            Tra(i,u)
            {
                DFS(v);
                price[u]+=price[v]*G.need(i);
                lim[u]=min(lim[u],lim[v]/G.need(i));
            }
            lim[u]=min(lim[u],m/price[u]);
            MEM(g,0xcf); g[0][0]=0;
            D(J,lim[u],0)
            {
                int t=0;
                Tra(i,u)
                {
                    ++t;
                    F(k,0,m) F(kk,0,k)
                    {
                        g[t][k]=max(g[t][k],g[t-1][kk]+f[v][J*G.need(i)][k-kk]);
                    }
                }
                F(j,0,J) F(k,0,m)
                {
                    f[u][j][k]=max(f[u][j][k],g[t][k]+(J-j)*power[u]);
                }
            }
        }
        int h[N][M];
        int mx[M];
        void Sakuya()
        {
            MEM(f,0xcf); MEM(g,0xcf); MEM(h,0xcf);
            h[0][0]=0;
            int t=0;
            F(i,1,n) if (fa[i]==-1)
            {
                DFS(i); ++t;
                F(k,0,m) 
                {
                    mx[k]=0;
                    F(j,0,lim[i]) mx[k]=max(mx[k],f[i][j][k]);
                }
                F(k,0,m) F(kk,0,k)
                {
                    h[t][k]=max(h[t][k],h[t-1][kk]+mx[k-kk]);
                }
            }
            int ans=0;
            F(i,0,m) ans=max(ans,h[t][i]);
            printf("%d
    ",ans);
        }
        void IsMyWife()
        {
            Input();
            Sakuya();
        }
    }
    #undef int //long long
    int main()
    {
        Flandre_Scarlet::IsMyWife();
        getchar();
        return 0;
    }
    
  • 相关阅读:
    Java高级之类结构的认识
    14.8.9 Clustered and Secondary Indexes
    14.8.4 Moving or Copying InnoDB Tables to Another Machine 移动或者拷贝 InnoDB 表到另外机器
    14.8.3 Physical Row Structure of InnoDB Tables InnoDB 表的物理行结构
    14.8.2 Role of the .frm File for InnoDB Tables InnoDB 表得到 .frm文件的作用
    14.8.1 Creating InnoDB Tables 创建InnoDB 表
    14.7.4 InnoDB File-Per-Table Tablespaces
    14.7.2 Changing the Number or Size of InnoDB Redo Log Files 改变InnoDB Redo Log Files的数量和大小
    14.7.1 Resizing the InnoDB System Tablespace InnoDB 系统表空间大小
    14.6.11 Configuring Optimizer Statistics for InnoDB 配置优化统计信息用于InnoDB
  • 原文地址:https://www.cnblogs.com/LightningUZ/p/14619687.html
Copyright © 2011-2022 走看看