zoukankan      html  css  js  c++  java
  • 2018.10.24 NOIP2018模拟赛 解题报告

    得分: \(100+0+100=200\)\(T2\)悲惨爆\(0\)

    \(P.S.\)由于原题是图片,所以我没有上传题目描述,只有数据。

    \(T1\):query(点此看题面

    熟悉主席树的人都知道,这是一道主席树查询区间排名的模板题。

    但是,由于太久没打主席树,我对它有一些生疏了,结果依然用了一个多小时... ...

    主席树查询区间排名的大致思路,就是将元素给离散化,然后用\(n\)棵线段树(合并成一棵主席树)分别存储\(1\sim i\)中每个元素出现次数,然后就可以很方便地利用前缀和思想查找了。

    代码如下:

    #include<bits/stdc++.h>
    #define max(x,y) ((x)>(y)?(x):(y))
    #define min(x,y) ((x)<(y)?(x):(y))
    #define uint unsigned int
    #define LL long long
    #define ull unsigned long long
    #define swap(x,y) (x^=y,y^=x,x^=y)
    #define abs(x) ((x)<0?-(x):(x))
    #define INF 1e9
    #define Inc(x,y) ((x+=(y))>=MOD&&(x-=MOD))
    #define ten(x) (((x)<<3)+((x)<<1))
    #define N 100000
    #define LogN 40
    using namespace std;
    int n,cnt,a[N+5],p[(N<<1)+5];
    struct Query
    {
        int l,r,val;
        Query(int x=0,int y=0,int z=0):l(x),r(y),val(z){}
    }q[N+5];
    class FIO
    {
        private:
            #define Fsize 100000
            #define tc() (FinNow==FinEnd&&(FinEnd=(FinNow=Fin)+fread(Fin,1,Fsize,stdin),FinNow==FinEnd)?EOF:*FinNow++)
            #define pc(ch) (FoutSize<Fsize?Fout[FoutSize++]=ch:(fwrite(Fout,1,FoutSize,stdout),Fout[(FoutSize=0)++]=ch))
            int f,FoutSize,OutputTop;char ch,Fin[Fsize],*FinNow,*FinEnd,Fout[Fsize],OutputStack[Fsize];
        public:
            FIO() {FinNow=FinEnd=Fin;}
            inline void read(int &x) {x=0,f=1;while(!isdigit(ch=tc())) f=ch^'-'?1:-1;while(x=ten(x)+(ch&15),isdigit(ch=tc()));x*=f;}
            inline void read_char(char &x) {while(isspace(x=tc()));}
            inline void read_string(string &x) {x="";while(isspace(ch=tc()));while(x+=ch,!isspace(ch=tc())) if(!~ch) return;}
            inline void write(int x) {if(!x) return (void)pc('0');if(x<0) pc('-'),x=-x;while(x) OutputStack[++OutputTop]=x%10+48,x/=10;while(OutputTop) pc(OutputStack[OutputTop]),--OutputTop;}
            inline void write_char(char x) {pc(x);}
            inline void write_string(string x) {register int i,len=x.length();for(i=0;i<len;++i) pc(x[i]);}
            inline void end() {fwrite(Fout,1,FoutSize,stdout);}
    }F;
    class Class_ChairmanTree//主席树
    {
        private:
            #define PushUp(rt) (node[rt].Size=node[node[rt].Son[0]].Size+node[node[rt].Son[1]].Size+1)//上传操作
            int n,tot,v,data[N+5],Root[N+5];
            struct Tree
            {
                int Son[2],Size,Cnt;
                inline void Clear() {Son[0]=Son[1]=Size=Cnt=0;}
            }node[N*LogN+5];
            inline void Build(int l,int r,int &rt)//建一棵初始的空树
            {
                rt=++tot;//新建一个节点,用了动态开点
                register int mid=l+r>>1;
                if(l^r) Build(l,mid,node[rt].Son[0]),Build(mid+1,r,node[rt].Son[1]);//建树
            }
            inline void Upt(int l,int r,int lst,int &rt,int pos)//将pos的出现次数加1
            {
                node[rt=++tot]=node[lst],++node[rt].Size;//新建一个节点,将子树大小加1
                if(!(l^r)) return (void)(++node[rt].Cnt);//如果是叶子节点,将出现次数加1
                register int mid=l+r>>1;
                pos<=mid?Upt(l,mid,node[lst].Son[0],node[rt].Son[0],pos):Upt(mid+1,r,node[lst].Son[1],node[rt].Son[1],pos);//继续操作子树
            }
            inline int get_rank(int l,int r,int rt,int val)//求出val在[l,r]区间内的排名
            {
                if(l>r) return 0;//如果l>r,返回0
                register int mid=l+r>>1;
                if(r<=val) return node[rt].Size;//如果右边界小于等于val,返回这棵子树的大小
                if(mid<val) return node[node[rt].Son[0]].Size+get_rank(mid+1,r,node[rt].Son[1],val);//如果左边界小于val,返回左子树的大小加上在右子树中询问的结果
                else return get_rank(l,mid,node[rt].Son[0],val);//否则,返回在左子树中询问的结果
            }
        public:
            inline void Clear() {for(register int i=0;i<=tot;++i) node[i].Cnt;tot=v=0;}//清空
            inline void Init(int len) {Build(1,n=len,Root[0]);}//建树
            inline void Add(int pos) {++v,Upt(1,n,Root[v-1],Root[v],pos);}//将某个元素出现次数加1
            inline int GetRank(int l,int r,int val) {return get_rank(1,n,Root[r],val)-get_rank(1,n,Root[l-1],val);}//求区间排名
    }ChairmanTree;
    inline int get_pos(int val)//求元素离散化后的值
    {
        register int l=1,r=cnt,mid=l+r>>1;
        for(;l<=r;mid=l+r>>1) p[mid]<val?l=mid+1:r=mid-1;
        return l;
    }
    int main()
    {
        register int i,T,Q,x,y,z;F.read(T);
        while(T--)
        {
        	for(ChairmanTree.Clear(),cnt=0,F.read(n),F.read(Q),i=1;i<=n;++i) F.read(a[i]),p[++cnt]=a[i];
        	for(i=1;i<=Q;++i) F.read(q[i].l),F.read(q[i].r),F.read(q[i].val),p[++cnt]=q[i].val;
        	for(sort(p+1,p+cnt+1),cnt=unique(p+1,p+cnt+1)-p-1,ChairmanTree.Init(cnt),i=1;i<=n;++i) ChairmanTree.Add(get_pos(a[i]));//建n棵线段树(合并成一棵主席树)
            for(i=1;i<=Q;++i) F.write(ChairmanTree.GetRank(q[i].l,q[i].r,get_pos(q[i].val))),F.write_char('\n');//输出答案
        }
        return F.end(),0;
    }
    

    \(T2\):assassin(点此看题面

    这题其实还是挺简单的,但比赛最后\(10\)分钟手贱把打了一半的代码给改炸了,最后爆\(0\)

    首先,我们将题目中给出的敌人分成两类:\(B_i=0\)(共\(cnt1\)个)和\(B_>=0\)(共\(cnt2\)个)。

    那么最终答案也无非两种情况:

    • 全部选\(B_i=0\)的。
    • 首先选择\(B_i>0\)\(A_i\)最小的敌人杀死。不难想到,既然杀死了一个\(B_i>0\)的敌人,则最优方案肯定是将所有\(B_i>0\)的敌人全部杀死。如果用\(sum\)表示\(\sum_{i=1}^n B_i\),则在杀死所有\(B_i>0\)的敌人后,我们还可以额外杀死\(sum-cnt2+1\)\(B_i=0\)的敌人,则根据贪心的思想,肯定是尽量选择\(A_i\)大的敌人杀死。然后对于剩下的敌人,再求出最多能杀死多少个即可。

    代码如下:

    #include<bits/stdc++.h>
    #define max(x,y) ((x)>(y)?(x):(y))
    #define min(x,y) ((x)<(y)?(x):(y))
    #define uint unsigned int
    #define LL long long
    #define ull unsigned long long
    #define swap(x,y) (x^=y,y^=x,x^=y)
    #define abs(x) ((x)<0?-(x):(x))
    #define INF 1e9
    #define Inc(x,y) ((x+=(y))>=MOD&&(x-=MOD))
    #define ten(x) (((x)<<3)+((x)<<1))
    #define N 100000
    using namespace std;
    int n,m,ans1,ans2,cnt1,cnt2,s1[N+5],s2[N+5];
    class FIO
    {
        private:
            #define Fsize 100000
            #define tc() (FinNow==FinEnd&&(FinEnd=(FinNow=Fin)+fread(Fin,1,Fsize,stdin),FinNow==FinEnd)?EOF:*FinNow++)
            #define pc(ch) (FoutSize<Fsize?Fout[FoutSize++]=ch:(fwrite(Fout,1,FoutSize,stdout),Fout[(FoutSize=0)++]=ch))
            int f,FoutSize,OutputTop;char ch,Fin[Fsize],*FinNow,*FinEnd,Fout[Fsize],OutputStack[Fsize];
        public:
            FIO() {FinNow=FinEnd=Fin;}
            inline void read(int &x) {x=0,f=1;while(!isdigit(ch=tc())) f=ch^'-'?1:-1;while(x=ten(x)+(ch&15),isdigit(ch=tc()));x*=f;}
            inline void read_char(char &x) {while(isspace(x=tc()));}
            inline void read_string(string &x) {x="";while(isspace(ch=tc()));while(x+=ch,!isspace(ch=tc())) if(!~ch) return;}
            inline void write(int x) {if(!x) return (void)pc('0');if(x<0) pc('-'),x=-x;while(x) OutputStack[++OutputTop]=x%10+48,x/=10;while(OutputTop) pc(OutputStack[OutputTop]),--OutputTop;}
            inline void write_char(char x) {pc(x);}
            inline void write_string(string x) {register int i,len=x.length();for(i=0;i<len;++i) pc(x[i]);}
            inline void end() {fwrite(Fout,1,FoutSize,stdout);}
    }F;
    inline void Solve(int x,int s,int t)//对最多有x个敌人可杀,剩余的耐久度为s,且已经杀死敌人数为t时的情况进行处理
    {
        register int i,res=t; 
        for(i=1;i<=x&&s+s1[i]<=m;++i) s+=s1[i];//尽量多杀
        if((res+=min(i-1,x))>ans1) ans1=res,ans2=s;//更新答案
        else if(!(ans1^res)&&s<ans2) ans2=s;
    }
    int main()
    {
        int i,j,T,x,y,sum;F.read(T);
        while(T--)
        {
        	for(F.read(n),F.read(m),sum=ans1=ans2=cnt1=cnt2=0,i=1;i<=n;++i) F.read(x),F.read(y),sum+=y,y?s2[++cnt2]=x:s1[++cnt1]=x;//将敌人分两种类别存储
        	sort(s1+1,s1+cnt1+1),sort(s2+1,s2+cnt2+1),Solve(cnt1,0,0);//排序,处理全选B[i]=0的敌人的情况
        	if(cnt2)//如果有B[i]>0的敌人
            {
                for(i=2;i<=cnt2;++i) s1[cnt1+i-1]=s2[i];//将除第一个以外的B[i]>0的敌人与B[i]=0的敌人存储在一起
                if(sort(s1+1,s1+cnt1+cnt2),s2[1]<=m) Solve(cnt1-(sum-cnt2+1),s2[1],sum+1);//排序+求解,个人认为还是比较好理解的
            }
        	F.write(ans1),F.write_char(' '),F.write(ans2),F.write_char('\n');//输出答案
        }
        return F.end(),0;
    }
    

    \(T3\):group(点此看题面

    原题: 【洛谷2519】[HAOI2011] problem a

    注意,原题中输出与此题刚好相反,直接输出\(Max\)即可。

    代码如下:

    #include<bits/stdc++.h>
    #define max(x,y) ((x)>(y)?(x):(y))
    #define min(x,y) ((x)<(y)?(x):(y))
    #define uint unsigned int
    #define LL long long
    #define ull unsigned long long
    #define swap(x,y) (x^=y,y^=x,x^=y)
    #define abs(x) ((x)<0?-(x):(x))
    #define INF 1e9
    #define Inc(x,y) ((x+=(y))>=MOD&&(x-=MOD))
    #define ten(x) (((x)<<3)+((x)<<1)) 
    #define N 100000
    using namespace std;
    int n,cnt=0,cnt_=0,a[N+5],f[N+5];
    struct Interval//存储区间信息
    {
        int l,r,v;//l和r表示边界,v表示出现次数
        Interval(int x=0,int y=0):l(x),r(y){v=1;}
        inline friend bool operator < (Interval x,Interval y) {return x.r^y.r?x.r<y.r:x.l<y.l;}
        inline friend bool operator == (Interval x,Interval y) {return !(x.l^y.l||x.r^y.r);}
    }s[N+5]; 
    class FIO
    {
        private:
            #define Fsize 100000
            #define tc() (FinNow==FinEnd&&(FinEnd=(FinNow=Fin)+fread(Fin,1,Fsize,stdin),FinNow==FinEnd)?EOF:*FinNow++)
            #define pc(ch) (FoutSize<Fsize?Fout[FoutSize++]=ch:(fwrite(Fout,1,FoutSize,stdout),Fout[(FoutSize=0)++]=ch))
            int f,FoutSize,OutputTop;char ch,Fin[Fsize],*FinNow,*FinEnd,Fout[Fsize],OutputStack[Fsize];
        public:
            FIO() {FinNow=FinEnd=Fin;}
            inline void read(int &x) {x=0,f=1;while(!isdigit(ch=tc())) f=ch^'-'?1:-1;while(x=ten(x)+(ch&15),isdigit(ch=tc()));x*=f;}
            inline void read_char(char &x) {while(isspace(x=tc()));}
            inline void read_string(string &x) {x="";while(isspace(ch=tc()));while(x+=ch,!isspace(ch=tc())) if(!~ch) return;}
            inline void write(int x) {if(!x) return (void)pc('0');if(x<0) pc('-'),x=-x;while(x) OutputStack[++OutputTop]=x%10+48,x/=10;while(OutputTop) pc(OutputStack[OutputTop]),--OutputTop;}
            inline void write_char(char x) {pc(x);}
            inline void write_string(string x) {register int i,len=x.length();for(i=0;i<len;++i) pc(x[i]);}
            inline void end() {fwrite(Fout,1,FoutSize,stdout);}
    }F;
    inline int find(int x,int len)//二分出一个最大的res使a[res]<x,实现O(logN)转移
    {
        register int l=0,r=len,mid=l+r+1>>1;
        for(;l<r;mid=l+r+1>>1) a[mid]<x?l=mid:r=mid-1;
        return l;
    }
    int main()
    {
        register int i,j,T,x,y,res,Max;F.read(T);
        while(T--)
        {
        	for(F.read(n),i=1,cnt=cnt_=Max=0;i<=n;++i) F.read(x),F.read(y),x+y<n&&(s[++cnt_]=Interval(x+1,n-y),0),a[i]=INF;//存储区间,注意将a数组初始化为INF
        	for(sort(s+1,s+cnt_+1),i=1;i<=cnt_;++i) cnt&&s[cnt]==s[i]?s[cnt].v=min(s[cnt].v+1,s[cnt].r-s[cnt].l+1):s[++cnt]=s[i];//去重
        	for(i=1;i<=cnt;++i)//枚举区间 
            {
                for(res=find(s[i].l,Max),j=res+1,f[i]=res+s[i].v;j<=f[i];++j) a[j]=min(a[j],s[i].r);//转移+更新a数组
                Max=max(Max,f[i]);//更新最大值
            }
            F.write(Max),F.write_char('\n');//输出答案
        }
        return F.end(),0;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    Docker之设置加速器
    Nginx之美多商城前台部署
    Nginx之负载均衡
    Nginx之反向代理
    美多商城后台MIS系统部署之Nginx配置
    Nginx之server和location配置使用
    题解 P4721 【【模板】分治 FFT】
    题解 P3338 【[ZJOI2014]力】
    题解 CHSEQ22 【Chef and Favourite Sequence】
    题解 CF813F 【Bipartite Checking】
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Contest20181024.html
Copyright © 2011-2022 走看看