• [3.24校内训练赛by hzwer]


    来自FallDream的博客,未经允许,请勿转载,谢谢。

    -----------------------------------------------------------------------------

    hzwer这次不都出省选题了,干脆直接扔出了APIO三道+一道NOI,然后按照惯例最后留了一个模板题。有两道apio是2014的,以前做过了,剩下的题调来调去,还剩20分钟终于做完了。

    -------------------------------------------------------------------------------

    A.[apio2012] dispatching派遣

    给定一棵n个点的树和一个费用m,每个点有一个忍者,派遣它的费用是ci,它的领导力是li。你要选择一个点作为领导,并且在它的子树中(包括它)选出尽可能多的点,满足费用不超过m且选出的点的数量*领导的领导力最大。n<=100000  m,c,l<=10^9

    题解:这道题很多做法吧..首先费用少的肯定先选,我们每次肯定是从费用小的开始选,所以题目可以转换为求所有点的子树中最多能选几个点。

    做法1:平衡树/优先队列+启发式合并

    把费用装进一个平衡树/优先队列里面,然后启发式合并,合并次数是nlogn,总复杂度nlog^2n

    我的做法:树剖那样子标号,满足子树的dfs序连续,然后主席树,复杂度是nlogn

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #define MN 100000
    #define MM 5000000
    #define INF 2000000000
    #define ll long long
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    
    int n,dfn=0,cnt=0,mx[MN+5],size[MN+5],nl[MN+5],nr[MN+5],head[MN+5],id[MN+5],rt[MN+5];
    ll c[MN+5],l[MN+5],ans=0,m;
    struct edge{
        int to,next;
    }e[MN+5];
    struct TREE{
        int l,r,size;ll x;
    }T[MM+5];
    
    void ins(int f,int t)
    {
        e[++cnt]=(edge){t,head[f]};head[f]=cnt;
    }
    
    void dfs1(int x)
    {
        size[x]=1;mx[x]=0;int maxn=0;
        for(int i=head[x];i;i=e[i].next)
        {
            dfs1(e[i].to);
            size[x]+=size[e[i].to];
            if(size[e[i].to]>maxn){maxn=size[e[i].to];mx[x]=e[i].to;}
        }
    }
    
    void dfs2(int x)
    {
        nl[x]=++dfn;id[dfn]=x;
        if(mx[x]) dfs2(mx[x]);
        for(int i=head[x];i;i=e[i].next)
            if(e[i].to!=mx[x])
                dfs2(e[i].to);
        nr[x]=dfn; 
    }
    
    void ins(int x,int nx,ll c)
    {
        T[nx].size=T[x].size+1;T[nx].x=T[x].x+c;
        ll l=1,r=INF,mid;
        while(l<r)
        {
            mid=l+r>>1;
            if(c<=mid) 
            {
                T[nx].r=T[x].r;T[nx].l=++cnt;
                r=mid;nx=T[nx].l;x=T[x].l;
            }
            else
            {
                T[nx].l=T[x].l;T[nx].r=++cnt;
                l=mid+1;nx=T[nx].r;x=T[x].r;
            }
            T[nx].size=T[x].size+1;T[nx].x=T[x].x+c;
        }
    }
    
    int query(int x,int nx,ll cc)
    {
        ll l=1,r=INF,mid,num=0;
        while(l<r)
        {
            mid=l+r>>1;
        //    cout<<T[T[nx].l].x-T[T[x].l].x<<" "<<T[T[nx].l].size-T[T[x].l].size<<endl;
            if(T[T[nx].l].x-T[T[x].l].x<=cc)
            {
                cc-=T[T[nx].l].x-T[T[x].l].x;
                num+=T[T[nx].l].size-T[T[x].l].size;
                x=T[x].r;nx=T[nx].r;l=mid+1;
            }
            else
            {
                x=T[x].l;nx=T[nx].l;
                r=mid;
            }
        }
        if(T[nx].size-T[x].size>0)
        {
            int x=cc/((T[nx].x-T[x].x)/(T[nx].size-T[x].size));
            num+=x;
        }
        return num;
    }
    
    main()
    {
        
        n=read();m=read();
        for(int i=1;i<=n;i++)
        {
            int fa=read();c[i]=read();l[i]=read();
            if(fa) ins(fa,i);
        }
        dfs1(1);dfs2(1);cnt=0;
        for(int i=1;i<=n;i++)
            ins(rt[i-1],rt[i]=++cnt,c[id[i]]);
        for(int i=1;i<=n;i++)
            ans=max(ans,l[i]*1LL*query(rt[nl[i]-1],rt[nr[i]],m));
    //    for(int i=1;i<=n;i++)
        //    cout<<i<<" "<<l[i]*1LL*query(rt[nl[i]-1],rt[nr[i]],m)<<endl;
        cout<<ans;
        return 0;
    }

    B.C是APIO2014的两道题,我已经写过题解啦  http://www.cnblogs.com/FallDream/p/apio2014.html

    D.[NOI2010]超级钢琴

    给定n个数,你要选出不同的k段区间,满足长度属于[l,r]并且总和最大。 n<=500000

    题解:我们发现以每个点作为左边界点,能选的区间都是连续的一段。我们可以从这一段中找到最值,然后扔到pq里面。

    每次我们从pq中取出最大的,然后那一段区间被我们选的那个数劈成了两半,我们对两半同样的做法,找到最值之后扔到pq,一直这么做直到拿出k个,就行啦。

    至于区间查最值  st表~线段树~看情况乱搞~

    复杂度nlogn

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #define MN 500005
    #define N 524288
    #define RG register 
    #define ll long long
    #define INF 1000000000000000000LL
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
     
    ll ans=0;
    int n,k,L,R,s[MN+5];
    struct data{
        ll x;int from;
        data operator + (data y)
        {
            return x>y.x?*this:y;
        }
        data operator -(ll num)
        {
            return (data){x-num,from};
        } 
    }t[N*2+5];
    struct node{int l,r,rg;data s;
        bool operator < (const node & y) const
        {
            return s.x<y.s.x;
        } 
    }now;
    priority_queue<node> q;
     
    data query(data*T,int l,int r)
    {
        data sum=(data){-INF,0};
        for(l+=N-1,r+=N+1;l^r^1;l>>=1,r>>=1)
        {
            if(~l&1) sum=sum+T[l+1];
            if( r&1) sum=sum+T[r-1];
        }
        return sum;
    }
     
    main()
    {
        n=read();k=read();L=read();R=read();
        for(int i=1;i<=N*2+1;i++)t[i]=(data){-INF,0};
        for(RG int i=1;i<=n;i++)s[i]=read()+s[i-1];
        for(RG int i=1;i<=n;i++) t[i+N]=(data){s[i],i};
        for(RG int i=N;i;i--) t[i]=t[i<<1]+t[i<<1|1];
        for(int i=1;i+L-1<=n;i++)
            q.push((node){i+L-1,min(i+R-1,n),i,query(t,i+L-1,min(i+R-1,n))-s[i-1]});
        for(int i=1;i<=k;i++)
        {
            now=q.top();q.pop();
            ans+=now.s.x;
            if(now.s.from-1>=now.l)
                q.push((node){now.l,now.s.from-1,now.rg,(query(t,now.l,now.s.from-1)-s[now.rg-1])});
            if(now.s.from+1<=now.r)
                q.push((node){now.s.from+1,now.r,now.rg,(query(t,now.s.from+1,now.r)-s[now.rg-1])});    
        }
        cout<<ans;
        return 0;
    }

    E.
    给定n个物品,每个物品有一个编号num和一个价值。你要取出一些物品,满足不存在一个非空子集满足异或和等于0,且价值最大。

    n<=1000      num<=10^18

    题解:显然排序之后按照价值大小添加最优,然后就是线性基裸题啦。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define MAXN 1005
    #define ll long long
    using namespace std;
    inline ll read()
    {
        ll x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
     
    int n;
    ll p[66];
    struct node{ll num;int x;}s[MAXN+5]; 
     
    bool cmp(node x,node y){return x.x>y.x;}
     
    int main()
    {
        n=read();
        for(int i=1;i<=n;i++) s[i].num=read(),s[i].x=read();
        sort(s+1,s+n+1,cmp);
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=60;j>=0;j--)
                if(s[i].num&(1LL<<j))
                    if(!p[j]) {p[j]=s[i].num;break;}
                    else s[i].num^=p[j];
            if(s[i].num>0)ans+=s[i].x;
            //cout<<i<<" "<<s[i].num<<endl;
        }
        cout<<ans;
        return 0;
    }
  • 相关阅读:
    reactnative 遍历本地图片地址,及避坑
    reactnative 类父组件调用子函数组件的方法
    reactnativesvg 使用
    reactnative 监听返回事件
    reactnative 使用日历 reactnativecommondatepicker
    reactnative Teaset微提示
    reactnative 子组件中进行路由跳转
    reactnative mobx状态管理
    reactnative类父组件调用类子组件的方法
    reactnative 实现阴影效果
  • 原文地址:https://www.cnblogs.com/FallDream/p/hzwer324.html
Copyright © 2020-2023  润新知