首页 > 其他分享 >多校A层冲刺NOIP2024模拟赛26

多校A层冲刺NOIP2024模拟赛26

时间:2024-11-26 17:59:52浏览次数:7  
标签:node 26 cnt int 多校 ans 500010 NOIP2024 struct

多校A层冲刺NOIP2024模拟赛26

\(T1\) A. 随机游走 \(100pts/100pts\)

  • 在树上做临项交换即可。

    点击查看代码
    struct node
    {
        ll nxt,to,w;
    }e[500010];
    ll head[500010],v[500010],siz[500010],sum[500010],cnt=0,ans=0,tim=0;
    struct quality
    {
        ll sumt,siz,to,w;
    };
    vector<quality>E[500010];
    bool cmp(quality a,quality b)
    {
        return a.sumt*b.siz<b.sumt*a.siz;
    }
    void add(ll u,ll v,ll w)
    {
        cnt++;
        e[cnt].nxt=head[u];
        e[cnt].to=v;
        e[cnt].w=w;
        head[u]=cnt;
    }
    void dfs1(ll x)
    {
        siz[x]=v[x];
        for(ll i=head[x];i!=0;i=e[i].nxt)
        {
            dfs1(e[i].to);
            siz[x]+=siz[e[i].to];
            sum[x]+=sum[e[i].to]+e[i].w;
            E[x].push_back((quality){e[i].w+sum[e[i].to],siz[e[i].to],e[i].to,e[i].w});
        }
        sort(E[x].begin(),E[x].end(),cmp);
    }
    void dfs2(ll x)
    {
        for(ll i=0;i<E[x].size();i++)
        {
            tim+=E[x][i].w;
            ans+=tim*v[E[x][i].to];
            dfs2(E[x][i].to);
        }
    }
    int main()
    {
        freopen("walk.in","r",stdin);
        freopen("walk.out","w",stdout);
        ll n,u,w,i;
        scanf("%lld",&n);
        for(i=2;i<=n;i++)
        {
            scanf("%lld%lld",&u,&w);
            add(u,i,w);
        }
        for(i=1;i<=n;i++)
        {
            cin>>v[i];
        }
        dfs1(1);
        dfs2(1);
        printf("%lld\n",ans);
        return 0;
    }
    

\(T2\) B. 分发奖励 \(68pts/68pts\)

  • 部分分

    • \(68pts\)
      • 先通过 \(DFS\) 序将树上问题转化为序列问题,然后线段树分治套一个支持区间推平的数据结构即可。

      • 赛时犯唐直接写了 \(O(\log n)\) 棵珂朵莉树暴力复制父亲节点信息,且还在好奇为什么改成线段树后 \(n \le 3000\) 的数据点都跑不过去。

        点击查看代码
        struct node
        {
            int nxt,to;
        }e[500010];
        int head[500010],dfn[500010],out[500010],pos[500010],ans[500010],tot=0,cnt=0;
        pair<int,int>val,val1,val2;
        void add(int u,int v)
        {
            cnt++;
            e[cnt].nxt=head[u];
            e[cnt].to=v;
            head[u]=cnt;
        }
        void dfs(int x)
        {
            tot++;
            dfn[x]=tot;
            pos[tot]=x;
            for(int i=head[x];i!=0;i=e[i].nxt)
            {
                dfs(e[i].to);
            }
            out[x]=tot;
        }
        struct ODT
        {
            struct node
            {
                int l,r;
                mutable int col;
                bool operator < (const node &another) const
                {
                    return l<another.l;
                }
            };
            int ans;
            set<node>s;
            void init(int n)
            {
                ans=0;
                s.insert((node){1,n,0});
            }
            set<node>::iterator split(int pos)
            {
                set<node>::iterator it=s.lower_bound((node){pos,0,0});
                if(it!=s.end()&&it->l==pos)
                {
                    return it;
                }
                it--;
                if(it->r<pos)
                {
                    return s.end();
                }
                int l=it->l,r=it->r,col=it->col;
                s.erase(it);
                s.insert((node){l,pos-1,col});
                return s.insert((node){pos,r,col}).first;
            }
            void assign(int l,int r,int col)
            {
                set<node>::iterator itr=split(r+1),itl=split(l);
                for(set<node>::iterator it=itl;it!=itr;it++)
                {
                    ans-=(it->col)*(it->r-it->l+1);
                }
                ans+=r-l+1;
                s.erase(itl,itr);
                s.insert((node){l,r,col});
            }
        }O[25];
        struct SMT
        {
            struct SegmentTree
            {
                vector<pair<int,int> >info;
            }tree[2000010];
            #define lson(rt) (rt<<1)
            #define rson(rt) (rt<<1|1)
            void update1(int rt,int l,int r,int x,int y)
            {
                if(x<=l&&r<=y)
                {
                    tree[rt].info.push_back(val);
                    return;
                }
                int mid=(l+r)/2;
                if(x<=mid)
                {
                    update1(lson(rt),l,mid,x,y);
                }
                if(y>mid)
                {
                    update1(rson(rt),mid+1,r,x,y);
                }
            }	
            void update2(int rt,int l,int r,int x,int y)
            {
                if(x<=l&&r<=y)
                {
                    tree[rt].info.push_back(val1);
                    tree[rt].info.push_back(val2);
                    return;
                }
                int mid=(l+r)/2;
                if(x<=mid)
                {
                    update2(lson(rt),l,mid,x,y);
                }
                if(y>mid)
                {
                    update2(rson(rt),mid+1,r,x,y);
                }
            }	
            void solve(int rt,int l,int r,int dep)
            {
                for(int i=0;i<tree[rt].info.size();i++)
                {
                    O[dep].assign(tree[rt].info[i].first,tree[rt].info[i].second,1);
                }
                if(l==r)
                {
                    ans[pos[l]]=max(O[dep].ans-1,0);
                    return;
                }
                else
                {
                    int mid=(l+r)/2;
                    O[dep+1]=O[dep];
                    solve(lson(rt),l,mid,dep+1);
                    O[dep+1]=O[dep];
                    solve(rson(rt),mid+1,r,dep+1);
                }
            }
        }T;
        int main()
        {
            freopen("reward.in","r",stdin);
            freopen("reward.out","w",stdout);
            int n,m,u,a,b,i;
            scanf("%d%d",&n,&m);
            for(i=2;i<=n;i++)
            {
                scanf("%d",&u);
                add(u,i);
            }
            dfs(1);
            for(i=1;i<=m;i++)
            {
                scanf("%d%d",&a,&b);
                if(a==b)
                {
                    val=make_pair(dfn[a],out[a]);
                    T.update1(1,1,n,dfn[a],out[a]);	
                }
                else
                {
                    val1=make_pair(dfn[a],out[a]);
                    val2=make_pair(dfn[b],out[b]);
                    T.update2(1,1,n,dfn[a],out[a]);
                    T.update2(1,1,n,dfn[b],out[b]);
                }
            }
            O[1].init(n);
            T.solve(1,1,n,1);
            for(i=1;i<=n;i++)
            {
                printf("%d ",ans[i]);
            }
            return 0;
        }
        
  • 正解

    • 转化为序列问题再套线段树分治是不必要的,因为完全可以在原树上再 \(DFS\) 一遍得到相同结果。
    • 可撤销数据结构可以用可持久化平衡树实现珂朵莉树或主席树或线段树维护最小值及最小值出现次数(可以证明最小值不会 \(<0\) )。
    点击查看代码
    struct node
    {
        int nxt,to;
    }e[500010];
    int head[500010],dfn[500010],out[500010],ans[500010],tot=0,cnt=0,n;
    vector<int>q[500010];
    void add(int u,int v)
    {
        cnt++;
        e[cnt].nxt=head[u];
        e[cnt].to=v;
        head[u]=cnt;
    }
    void dfs(int x)
    {
        tot++;
        dfn[x]=tot;
        for(int i=head[x];i!=0;i=e[i].nxt)
        {
            dfs(e[i].to);
        }
        out[x]=tot;
    }
    struct PDS_SMT
    {
        int root[500010],rt_sum;
        struct SegmentTree
        {
            int ls,rs,lazy,sum;
        }tree[500010<<7];
        #define lson(rt) (tree[rt].ls)
        #define rson(rt) (tree[rt].rs)
        int build_rt()
        {
            rt_sum++;
            lson(rt_sum)=rson(rt_sum)=tree[rt_sum].lazy=tree[rt_sum].sum=0;
            return rt_sum;
        }
        void pushup(int rt)
        {
            tree[rt].sum=tree[lson(rt)].sum+tree[rson(rt)].sum;
        }
        void update(int pre,int &rt,int l,int r,int x,int y)
        {
            rt=build_rt();
            tree[rt]=tree[pre];
            if(tree[rt].lazy==1||(x<=l&&r<=y))
            {
                tree[rt].lazy=1;
                tree[rt].sum=r-l+1;
                return;
            }
            int mid=(l+r)/2;
            if(x<=mid)
            {
                update(lson(pre),lson(rt),l,mid,x,y);
            }
            if(y>mid)
            {
                update(rson(pre),rson(rt),mid+1,r,x,y);
            }
            pushup(rt);
        }
    }T;
    void solve(int x,int fa)
    {
        T.root[x]=T.root[fa];
        for(int i=0;i<q[x].size();i++)
        {
            T.update(T.root[x],T.root[x],1,n,dfn[q[x][i]],out[q[x][i]]);
        }
        ans[x]=max(T.tree[T.root[x]].sum-1,0);
        for(int i=head[x];i!=0;i=e[i].nxt)
        {
            solve(e[i].to,x);
        }
    }
    int main()
    {
        freopen("reward.in","r",stdin);
        freopen("reward.out","w",stdout);
        int m,u,a,b,i;
        scanf("%d%d",&n,&m);
        for(i=2;i<=n;i++)
        {
            scanf("%d",&u);
            add(u,i);
        }
        dfs(1);
        for(i=1;i<=m;i++)
        {
            scanf("%d%d",&a,&b);
            q[a].push_back(a);
            q[a].push_back(b);
            q[b].push_back(a);
            q[b].push_back(b);
        }
        solve(1,0);
        for(i=1;i<=n;i++)
        {
            printf("%d ",ans[i]);
        }
        return 0;
    }
    

\(T3\) C. 卡路里 \(0pts/0pts\)

  • 部分分

    • 测试点 \(1 \sim 5\) :特殊性质加状压 \(DP\) 。
    点击查看代码
    ll a[5010][210],d[5010],sum[5010],f[10][(1<<10)+10];
    int main()
    {
        freopen("calorie.in","r",stdin);
        freopen("calorie.out","w",stdout);
        ll n,m,ans=-0x3f3f3f3f,flag=1,num,i,j,k,h,v;
        scanf("%lld%lld",&n,&m);
        for(i=2;i<=m;i++)
        {
            scanf("%lld",&d[i]);
            sum[i]=sum[i-1]+d[i];
        }
        for(i=1;i<=m;i++)
        {
            for(j=1;j<=n;j++)
            {
                scanf("%lld",&a[i][j]);
            }
            for(j=2;j<=n;j++)
            {
                flag&=(a[i][j]==a[i][j-1]);
            }
        }
        if(n>=8)
        {
            ans=0;
            if(flag==1)
            {
                for(i=1;i<=m;i++)
                {
                    ans=max(ans,a[i][1]*n);
                }
            }
            else
            {
                for(i=1;i<=n;i++)
                {
                    ans+=a[1][i];
                }
            }
        }
        else
        {
            memset(f,-0x3f,sizeof(f));
            f[0][0]=0;
            for(i=1;i<=m;i++)
            {
                for(v=0;v<=i-1;v++)
                {
                    for(j=0;j<=(1<<n)-1;j++)
                    {
                        for(k=j;k!=0;k=j&(k-1))
                        {
                            num=0;
                            for(h=0;h<=n-1;h++)
                            {
                                num+=((k>>h)&1)*a[i][h+1];
                            }
                            f[i][j]=max(f[i][j],f[v][j^k]+num-(v!=0)*(sum[i]-sum[v]));
                        }
                    }
                }
                ans=max(ans,f[i][(1<<n)-1]);
            }
        }
        printf("%lld\n",ans);
        return 0;
    }
    
    
  • 正解

    • 观察到最优情况一定形如选择一段区间 \([l,r]\) 然后从某一个端点走到另一个端点,每款奶茶选择区间内卡路里最大的店购买。
    • 不妨钦定从左往右走,并在卡路里相同时选择最靠左的店买奶茶。
    • 单调栈处理出每款奶茶所能覆盖的区间,然后就得到了每款奶茶对于询问区间的贡献。
    • 先对二维平面加差分后再做二维前缀和即可。
    点击查看代码
    ll a[5010][210],d[5010],sum[5010][5010],l[5010],r[5010];
    stack<ll>s;
    int main()
    {
        freopen("calorie.in","r",stdin);
        freopen("calorie.out","w",stdout);
        ll n,m,ans=-0x7f7f7f7f,i,j;
        scanf("%lld%lld",&n,&m);
        for(i=2;i<=m;i++)
        {
            scanf("%lld",&d[i]);
            d[i]+=d[i-1];
        }
        for(i=1;i<=m;i++)
        {
            for(j=1;j<=n;j++)
            {
                scanf("%lld",&a[i][j]);
            }
        }
        for(j=1;j<=n;j++)
        {
            while(s.empty()==0)
            {
                s.pop();
            }
            for(i=1;i<=m;i++)
            {
                while(s.empty()==0&&a[s.top()][j]<=a[i][j])
                {
                    s.pop();
                }
                l[i]=(s.empty()==0)?s.top()+1:1;
                s.push(i);
            }
            while(s.empty()==0)
            {
                s.pop();
            }
            for(i=m;i>=1;i--)
            {
                while(s.empty()==0&&a[s.top()][j]<a[i][j])
                {
                    s.pop();
                }
                r[i]=(s.empty()==0)?s.top()-1:m;
                s.push(i);
            }
            for(i=1;i<=m;i++)
            {
                sum[l[i]][i]+=a[i][j];
                sum[i+1][r[i]+1]+=a[i][j];
                sum[i+1][i]-=a[i][j];
                sum[l[i]][r[i]+1]-=a[i][j];
            }
        }
        for(i=1;i<=m;i++)
        {
            for(j=1;j<=m;j++)
            {
                sum[i][j]+=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
                if(j>=i)
                {
                    ans=max(ans,sum[i][j]+d[i]-d[j]);	
                }
            }
        }
        printf("%lld\n",ans);
        return 0;
    }
    

\(T4\) D. 传话游戏 \(4pts/4pts\)

总结

  • 赛时后两个半小时基本全在写 \(T3\) 的 \(O(m^{2}3^{n}n)\) 的部分分,最后半个小时才想起来补 \(T3\) 的两个特殊性质和 \(T4\) 的一个特殊性质。
  • \(T3\) 炸 int 了,挂了 \(25pts\) 。

后记

  • \(T2\)
    • 下发的 \(PDF\) 上写的时限为 \(1s\) ,但在 \(OJ\) 上改成了 \(4s\) 。
    • 数据中没有造 \(a_{i}=b_{i}\) 的特殊性质。

标签:node,26,cnt,int,多校,ans,500010,NOIP2024,struct
From: https://www.cnblogs.com/The-Shadow-Dragon/p/18570710

相关文章

  • Docker/DockerHub 国内镜像源/加速列表(11月26日更新-长期维护)
    前言本列表为科研工作者提供docker镜像网站,网络不好的同学可以使用镜像,或者推荐给身边有需要的朋友使用这些docker镜像。注意:仅供学术研究使用。⚠️长期更新,建议收藏!更新日志11月25日新增:https://docker.linkedbus.com(推荐)11月24日新增:https://docke......
  • 2024.11.26模拟赛
    昨天也打了模拟赛。但没补没总结。为什么呢。因为懒。今天来了之后先犯困了一个坤小时。犯困的那两个半小时属于是连暴力都没法想怎么去写的那种。好不容易慢慢清醒了,又不想写了。随便打了个T3的暴力,又写了个T1的爆搜,结果爆搜炸了。所以,今天昨天打的都很不怎么样。结果考完之后......
  • 11.26 CW 模拟赛 赛时记录
    看题也是给他绑上\(\rm{Subtask}\)了,这我骗鸡毛分啊感冒也是非常难受,但是事已至此,先读题吧题目背景好看爱看\(\rm{T1}\)图论题,好玩\(\rm{T2}\)大概也是不会做,再说\(\rm{T3}\)难绷,考虑高档暴力\(\rm{T4}\)这个肯定是暴力都难打今天也是\(30\rm{min}......
  • H.265流媒体播放器EasyPlayer.js播放器关于播放内网https地址报错(ERR_CERT_COMMON_NA
    随着技术的发展,越来越多的H5流媒体播放器开始支持H.265编码格式。例如,EasyPlayer.jsH5播放器能够支持H.264、H.265等多种音视频编码格式,这使得播放器能够适应不同的视频内容和网络环境。那么播放内网https地址报错(ERR_CERT_COMMON_NAME_INVALID错误)怎么处理?一般这种情况是浏览......
  • [2024.11.26]NOIP模拟赛
    挂分+不会+暴力场。赛时T1看到大样例里面的输出后意识到这题需要高精。乘法高精讲的时候没听,但是后来不知道从哪看到这就是所谓的加法卷积,所以直接按照卷积的形式写就行了。然后开始看题,感觉特别像打表找规律。看着样例觉得是蛇形填充,写完以后自己造了个样例发现随便组合都......
  • 打卡信奥刷题(309)用C++信奥P2614[普及组/提高] 计算器弹琴
    计算器弹琴题目描述总所周知,计算器可以拿来干很多它本不应该干的事情,比如写作文。(参看洛谷P2549)小A发现了一个计算器的另一个隐藏功能——弹琴。http://www.bilibili.com/video/av2205500/如果按上一个键,比如说1,就会发出中音“Do”。这边给出按键音高表+低音Fa<低......
  • SpringBoot游泳馆会员管理系统q26c5 带论文文档1万字以上,文末可获取
    开题报告内容一、选题背景与意义随着健康意识的提升,游泳馆作为重要的健身场所,其会员管理效率直接影响到顾客体验和经营效益。传统的会员管理方式存在信息记录不全、查询不便、服务不精准等问题。因此,开发一套高效、智能的游泳馆会员管理系统具有重要意义,旨在提升会员服务质量......
  • 代码随想录——26、二叉(搜索)树的最近公共祖先
    递归最近公共祖先定义:设节点root为节点p,q的某公共祖先,若其左子节点root.left和右子节点root.right都不是p,q的公共祖先,则称root是“最近的公共祖先”。若root是p,q的最近公共祖先,则只可能为以下情况之一如果p和q在节点root的两侧,那么root就是最近公共祖先p......
  • 【SPSS 26 软件下载与安装教程】
    1、安装包 SPSS26:下载地址 2、安装教程1)       解压下载安装包,点击setup.exe可执行文件  2)        弹窗安装对话框,选择安装IBMSPSS26  3)        读取安装进度条,选择下一步  4)        选择我接受,点击下一步  ......
  • NOip2024前最后一周训练日记
    也是有了博客了,上周花了点时间稍微搭了一下界面。闲话初三生,目前为止初中去过三个学校。第一个学校。这时基本没怎么沾OI,只是靠机构和自学了解的,因此前两年的CSP都基本是不好。记得初一下的时候,GF组织算法冬令营,原本想着打比赛打的好一点去进本部校队的,但我发现了甚至零基......