训练日记-多校

  今天补了下昨天的题。

  首先是G题,数轴上有n个集装箱,第i个集装箱位于坐标x[i],有a[i]件货物。 现在要把集装箱进行一些移动,求在所有货物移动总距离不超过T的情况下,最多能把多少个物品移动到 同一个位置。

  这个题学习到的地方主要是如果物品移动有费用,如何把一个区间中的所有东西移动到一个点上,或者是表示一种带权路径的方法。还有一些能够二分的案例。

   然后就是H题,一棵树,点有点权。要选出三条不相交的链使得三条链的权值之和最大。
H题是一个树形dp题,看了这道题,感觉这个树形dp,确实很麻烦,在树形dp的过程中还有其他的dp,需要处理子树的最大值,这种思路需要借鉴。

   借鉴出题人题解和一些思路,自己尝试了一下。

  代码:

#include <bits/stdc++.h>

using namespace std;
#define ll long long
const int maxn=5e5+10;
const int INF =0x3f3f3f3f;
struct poin
{
    int v,next;
}G[maxn*2];
int head[maxn],ans,val[maxn];
ll dp[maxn][5];
ll cnt[maxn][5];
void add(int u,int v)
{
    G[ans].v=v;
    G[ans].next=head[u];
    head[u]=ans++;

    G[ans].v=u;
    G[ans].next=head[v];
    head[v]=ans++;
}
void init()
{
    memset(head,-1,sizeof(head));
    ans=0;
}

void dfs(int u,int fa)
{
    int twt=0;
    ll sum[2][5][5]={0},tmp[5][5]={0};
    for(int i=head[u];i!=-1;i=G[i].next)
    {
        int v=G[i].v;
        if(v==fa)continue;
        dfs(v,u);
        twt++;
        for(int j=0;j<=2;j++)
        {
            for(int k=0;k<=3;k++)
            {
                tmp[j][k]=0;
                sum[twt&1][j][k]=0;
            }
        }
        for(int j=0;j<=3;j++)
        {
            tmp[0][j]=dp[v][j];
            tmp[1][j]=cnt[v][j];
        }
        for(int x=0;x<=2;x++)
        {
            for(int y=0;x+y<=2;y++)
            {
                for(int p=0;p<=3;p++)
                {
                    for(int q=0;p+q<=3;q++)
                    {
                        sum[twt&1][x+y][p+q]=max(sum[twt&1][x+y][p+q],sum[(twt&1)^1][x][p]+tmp[y][q]);
                    }
                }
            }
        }
    }
    for(int i=0;i<=1;i++)
    {
        for(int j=0;j<=3;j++)
        {
            cnt[u][j]=max(cnt[u][j],val[u]+sum[twt&1][i][j]);
        }
    }
    for(int i=0;i<=2;i++)
    {
        for(int j=1;j<=3;j++)
        {
            dp[u][j]=max(dp[u][j],val[u]+sum[twt&1][i][j-1]);
        }
    }
    for(int j=0;j<=3;j++)
    {
        dp[u][j]=max(dp[u][j],sum[twt&1][0][j]);
    }

}
int n;
int main()
{
    while(~scanf("%d",&n))
    {
        init();
        ans=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&val[i]);
        }
        for(int i=1;i<n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v);
        }
        dfs(1,-1);
        printf("%lld\n",dp[1][3]);
    }
    return 0;
}

   

   j题,大约就是理解它的意思,我感觉,他的第二种做法,比较好,充分利用了二进制的性质,每个不同的数的二进制位数以哦对那个有不同的,利用这个来进行分类,以后可以利用一下这种方法。第三种随机数的方法也是听起来很奇妙,不过,不太稳定,不能保证一定可以过。

   晚上随便打了打牛客的小白月赛。也有几道题数学题比较不错,可以仔细研究,补充自己的不足。

   

扫描二维码关注公众号,回复: 2486881 查看本文章

猜你喜欢

转载自blog.csdn.net/a1046765624/article/details/81159386