zoukankan      html  css  js  c++  java
  • 2.19比赛

    noip套路赛

     非常非常非常NOIp的模拟赛(吐槽完毕)


    1、啊
    (paint.cpp/c/pas)
    【问题描述】

    小X现在正准备刷墙,墙的长度为n。

    但是刷墙不是一蹴而就的,所以他会刷m次墙,每次刷的是墙的连续的一段,有时候也会覆盖之前刷的部分。

    终于,墙刷完了,先在小X想问你从 1~n 块墙分别是什么时候刷的

    【输入格式】

    输入文件名为paint.in 
    第一行两个数n,m表示墙的长度和刷墙次数

    第二行两个数p,q表示种子

    第i次询问的两个端点分别是 (i*p+q)%n+1 , (i*q+p)%n+1

     

    【输出格式】

    输出文件名为paint.out
    共n行,每行一个整数表示第i块墙最后被刷的时间,如果没被刷到输出0

    【输入样例】

    4 3 
    2 4 

    【输出样例】

    2

    3

    3

    【数据规模与约定】

    对于30%的数据, 1<=n,m<=3000

    对于50%的数据, 1<=n<=8000,m<=104

    对于80%的数据,1<=n<=5*105,m<=106

    对于100%的数据,1<=n<=106,1<=m<=107

    数据保证运算过程中不会爆int

    本题输出较大,建议使用所提供的快输

    原题:洛谷 2391白雪皑皑

    sol:首先经过漫长的思考,发现正着做怎么也弄不了

    于是就考虑倒过来做:此时惊喜的发现每个点只要染色一次就OK了,这就用并查集随便处理一下,如果x被染色了,Father[x]就是x+1,下次直接跳过就可以了

    #include <bits/stdc++.h>
    using namespace std;
    typedef int ll;
    inline ll read()
    {
        ll s=0;
        bool f=0;
        char ch=' ';
        while(!isdigit(ch))
        {
            f|=(ch=='-'); ch=getchar();
        }
        while(isdigit(ch))
        {
            s=(s<<3)+(s<<1)+(ch^48); ch=getchar();
        }
        return (f)?(-s):(s);
    }
    #define R(x) x=read()
    inline void write(ll x)
    {
        if(x<0)
        {
            putchar('-'); x=-x;
        }
        if(x<10)
        {
            putchar(x+'0');    return;
        }
        write(x/10);
        putchar((x%10)+'0');
        return;
    }
    #define W(x) write(x),putchar(' ')
    #define Wl(x) write(x),putchar('
    ')
    const int N=10000005;
    int n,m,seed1,seed2;
    int Cor[N];
    int Father[N];
    inline int Get_Father(int x)
    {
        int Fa=Father[x];
        while(Fa!=Father[Fa]) Fa=Father[Fa];
        while(x!=Father[x])
        {
            int oo=x;
            x=Father[x];
            Father[oo]=Fa;
        }
        return Fa;
    }
    int main()
    {
        freopen("paint.in","r",stdin);
        freopen("paint.out","w",stdout);
        int i,j;
        R(n); R(m); R(seed1); R(seed2);
        for(i=1;i<=n+1;i++) Father[i]=i;
        for(i=m;i>=1;i--)
        {
            int l=((long long)(seed1*i+seed2))%n+1,r=((long long)(seed2*i+seed1))%n+1;
            if(l>r) swap(l,r);
            for(j=l;j<=r;)
            {
                int Fa=Get_Father(j);
                if(Fa==j)
                {
                    Cor[j]=i; Father[j]=j+1;
                }
                j=Fa;
            }
        }
        for(i=1;i<=n;i++)
        {
            Wl(Cor[i]);
        }
        return 0;
    }
    /*
    input
    4 3
    2 4
    output
    2
    3
    3
    0
    */
    View Code
    2、六
    (plant.cpp/c/pas)
    【问题描述】

    并查集真好用,现在有n个并查集,围成了一圈,每个并查集有一个ac值

    你必须从中取出m个并查集,使他们的ai和最大,这样才可以ac此题。

    值得一提的是你不可以选择两个相邻的并查集(1和n也相连),这样他们会连在一起,产生爆0气息。

    【输入格式】

    输入文件名为plant.in 

    输入的第一行包含两个正整数n,m,分别表示并查集数和所选并查集数。

    第二行n个整数ai,表示第i个并查集的ac值。

    【输出格式】

    输出文件名为plant.out

    输出一个整数,表示最佳方案可以得到的ac值。如果无解输出“Error!”,不包含引号。

    【输入样例】

    7 3 
    1 2 3 4 5 6 7 

    【输出样例】

    15 

    【数据规模与约定】

    对于40%的数据,1<=n<=70

    对于55%的数据,1<=n<=200

    对于85%的数据,1<=n<=2000

    对于全部数据,1<=n<=2*105,-1000<=ai<=1000

    sol:原题是 51nod 夹克老爷的逢三抽一,思路清奇

    用的是堆贪心,其精髓在于反悔机制(摘自yj大佬原话),如果你选了x,则x-1和x+1都不在了,链表随便搞搞,然后在堆中加入一个ax-1+ax+1-ax

    #include <bits/stdc++.h>
    using namespace std;
    typedef int ll;
    inline ll read()
    {
        ll s=0;
        bool f=0;
        char ch=' ';
        while(!isdigit(ch))
        {
            f|=(ch=='-'); ch=getchar();
        }
        while(isdigit(ch))
        {
            s=(s<<3)+(s<<1)+(ch^48); ch=getchar();
        }
        return (f)?(-s):(s);
    }
    #define R(x) x=read()
    inline void write(ll x)
    {
        if(x<0)
        {
            putchar('-'); x=-x;
        }
        if(x<10)
        {
            putchar(x+'0');    return;
        }
        write(x/10);
        putchar((x%10)+'0');
        return;
    }
    #define W(x) write(x),putchar(' ')
    #define Wl(x) write(x),putchar('
    ')
    const int N=500005;
    int n,m,Val[N];
    int L[N],R[N];
    typedef pair<int,int> P;
    set<P>S;
    inline void Del(int x)
    {
        S.erase(P(Val[x],x));
        L[R[x]]=L[x];
        R[L[x]]=R[x];
        return;
    }
    int main()
    {
        freopen("plant.in","r",stdin);
        freopen("plant.out","w",stdout);
        int i,ans=0;
        R(n); R(m);
        if(m>(n>>1)) return 0*puts("Error!");
        for(i=1;i<=n;i++)
        {
            R(Val[i]);
            S.insert(P(Val[i],i));
            L[i]=(i-1+n-1)%n+1;
            R[i]=(i+1-1)%n+1;
        }
        for(i=1;i<=m;i++)
        {
            int Pos=S.rbegin()->second;
            S.erase(*S.rbegin());
            int k1=Val[L[Pos]],k=Val[Pos],k2=Val[R[Pos]];
            ans+=k;
            Del(L[Pos]);
            Del(R[Pos]);
            Val[Pos]=k1+k2-k;
            S.insert(P(Val[Pos],Pos));
        }
        Wl(ans);
        return 0;
    }
    /*
    input
    7 3 
    1 2 3 4 5 6 7
    output
    15
    */
    View Code
    3、好
    (build.cpp/c/pas)
    【问题描述】

    小W现在要去S国ak,S国有n个城市,但是各地之间的路还没有修好,所以他决定在ak的同时,也会参与道路的建设。

    所以现在有m个时刻,每个时刻可能会有两个城市之间的道路修好了,也有可能小W问你最早什么时候他可以从u城市到v城市

     

    【输入格式】

    输入文件名为build.in 

    第一行两个整数 n,m。

    接下来m行,每行0 u v 或 1 u v的形式

    0 u v 表示这两个城市之间建立了新的道路

    1 u v 表示小W的询问

    小W为了考验你,特地对数据精心加密,对于每次操作,真正的u,v都等于读入的u,v异或上一次的答案,一开始这个值为0。

    【输出格式】

    输出文件名为build.out

    对于每次询问,输出 u, v 最早在加入哪条边后可以互相到达,若到这个操作时还没联通,则输出 0。

    【输入样例】

    5 9 
    0 1 4 
    1 2 5 
    0 2 4 
    0 3 4 
    1 3 1 
    0 7 0 
    0 6 1 
    0 1 6 
    1 2 6 

    【输出样例】



    【数据规模与约定】

    对于30%的数据, 1<=n<=5000

    对于60%的数据,1<=n<=30000

     对于80%的数据,1<=n<=100000

     对于100%的数据,1<=n<=5*105

    sol:这大概是最水的一道了(不知道原题)

    强制在线用并查集做,对于x,y:直接按秩合并,树高就一直是log了,然后暴力找x,y之间最晚的那条边就好了

    #include <bits/stdc++.h>
    using namespace std;
    typedef int ll;
    inline ll read()
    {
        ll s=0;
        bool f=0;
        char ch=' ';
        while(!isdigit(ch))
        {
            f|=(ch=='-'); ch=getchar();
        }
        while(isdigit(ch))
        {
            s=(s<<3)+(s<<1)+(ch^48); ch=getchar();
        }
        return (f)?(-s):(s);
    }
    #define R(x) x=read()
    inline void write(ll x)
    {
        if(x<0)
        {
            putchar('-'); x=-x;
        }
        if(x<10)
        {
            putchar(x+'0');    return;
        }
        write(x/10);
        putchar((x%10)+'0');
        return;
    }
    #define W(x) write(x),putchar(' ')
    #define Wl(x) write(x),putchar('
    ')
    const int N=500005;
    int n,m;
    struct BingCJ
    {
        int Father[N],G[N],Depth[N];
        inline int Get_Father(int x)
        {
            if(Father[x]==x)
            {
                Depth[x]=1;
                return x;
            }
            else
            {
                int oo=Get_Father(Father[x]);
                Depth[x]=Depth[Father[x]]+1;
                return oo;
            }
        }
        inline void Merge(int x,int y,int T)
        {
            register int xx=Get_Father(x),yy=Get_Father(y);
            if(xx==yy) return;
            if(Depth[xx]<Depth[yy]) swap(xx,yy);
            Father[yy]=xx;
            G[yy]=T;
            if(Depth[xx]=Depth[yy]) Depth[xx]++;
            return;
        }
        inline int Solve(int x,int y)
        {
            register int xx=Get_Father(x),yy=Get_Father(y);
            if(xx!=yy) return 0;
            register int Dx=Depth[x],Dy=Depth[y];
            register int ans=0;
            while(x!=y)
            {
                if(Dx>Dy)
                {
                    ans=max(ans,G[x]); x=Father[x]; Dx--;
                }
                else
                {
                    ans=max(ans,G[y]); y=Father[y]; Dy--;
                }
            }
            return ans;
        }
        inline void Init()
        {
            register int i;
            for(i=1;i<=n;i++)
            {
                Father[i]=i;
                Depth[i]=1;
            }
        }
    }B;
    int main()
    {
        freopen("build.in","r",stdin);
        freopen("build.out","w",stdout);
        register int i,cnt=0,ans=0;
        R(n); R(m);
        B.Init();
        for(i=1;i<=m;i++)
        {
            int opt=read();
            int x=read()^ans,y=read()^ans;
            switch (opt)
            {
                case 0:
                    B.Merge(x,y,++cnt);
                    break;
                case 1:
                    ans=B.Solve(x,y);
                    Wl(ans);
                    break;
                default:
                    break;
            }
        }
        return 0;
    }
    View Code
    4、你
    (identity.cpp/c/pas)
    【问题描述】

    你在遗迹中发现了可以ak的秘宝——小W的身*证。

    小W太厉害了,所以他有n张身份证,这n张身*证排成一个序列。

    在遗迹中还有一本书,记录了身*证的用法,每个身*证有小W的一丝能量,能量也可能会造成伤害,你可以用一段连续的身*证发动一个大膜法,膜法的强度是身*证能量的和,同时膜法要求的数量是有限制的,不能太多也不能太少。

    现在,你急需借助小W的力量,所以你必须尽快知道前K大的膜法强度之和

    【输入格式】

    输入文件名为identity.in 

    第一行包含四个正整数n,k,l,r。其中n为身*证的个数,为膜法的数量限制,分别是膜法身*证所需数量的上下界

    接下来n个整数表示第张身*证的能量

    【输出格式】

    输出文件名为identity.out
    一个整数表示前K大的膜法强度之和

    【输入样例】

    8 4 1 6 
    1 -2 3 -4 5 -6 7 -8 

    【输出样例】

    23 

    【数据规模与约定】
    测试点NK
    1 10 100
    2 1000 500,000
    3 100,000 1
    4 10,000 10,000
    5 500,000 10,000
    6 80,000 80,000
    7 100,000 100,000
    8 100,000 500,000
    9 500,000 500,000
    10 500,000 500,000

     -1000<=ai<=1000,1<=L,R<=n

    原题:洛谷2048超级钢琴

    首先对于一个位置i,从i+L-1~i+R-1之间找到最大的,加入堆中(ST表轻松实现)

    然后如果i~x这段算过了,就把i+L-1,x-1和x+1,i+R-1这两段加进来,弄k次,就好了

    #include <bits/stdc++.h>
    using namespace std;
    typedef int ll;
    inline ll read()
    {
        ll s=0;
        bool f=0;
        char ch=' ';
        while(!isdigit(ch))
        {
            f|=(ch=='-'); ch=getchar();
        }
        while(isdigit(ch))
        {
            s=(s<<3)+(s<<1)+(ch^48); ch=getchar();
        }
        return (f)?(-s):(s);
    }
    #define R(x) x=read()
    inline void write(ll x)
    {
        if(x<0)
        {
            putchar('-'); x=-x;
        }
        if(x<10)
        {
            putchar(x+'0');    return;
        }
        write(x/10);
        putchar((x%10)+'0');
        return;
    }
    #define W(x) write(x),putchar(' ')
    #define Wl(x) write(x),putchar('
    ')
    const int N=500005;
    int n,m;
    struct BingCJ
    {
        int Father[N],G[N],Depth[N];
        inline int Get_Father(int x)
        {
            if(Father[x]==x)
            {
                Depth[x]=1;
                return x;
            }
            else
            {
                int oo=Get_Father(Father[x]);
                Depth[x]=Depth[Father[x]]+1;
                return oo;
            }
        }
        inline void Merge(int x,int y,int T)
        {
            register int xx=Get_Father(x),yy=Get_Father(y);
            if(xx==yy) return;
            if(Depth[xx]<Depth[yy]) swap(xx,yy);
            Father[yy]=xx;
            G[yy]=T;
            if(Depth[xx]=Depth[yy]) Depth[xx]++;
            return;
        }
        inline int Solve(int x,int y)
        {
            register int xx=Get_Father(x),yy=Get_Father(y);
            if(xx!=yy) return 0;
            register int Dx=Depth[x],Dy=Depth[y];
            register int ans=0;
            while(x!=y)
            {
                if(Dx>Dy)
                {
                    ans=max(ans,G[x]); x=Father[x]; Dx--;
                }
                else
                {
                    ans=max(ans,G[y]); y=Father[y]; Dy--;
                }
            }
            return ans;
        }
        inline void Init()
        {
            register int i;
            for(i=1;i<=n;i++)
            {
                Father[i]=i;
                Depth[i]=1;
            }
        }
    }B;
    int main()
    {
        freopen("build.in","r",stdin);
        freopen("build.out","w",stdout);
        register int i,cnt=0,ans=0;
        R(n); R(m);
        B.Init();
        for(i=1;i<=m;i++)
        {
            int opt=read();
            int x=read()^ans,y=read()^ans;
            switch (opt)
            {
                case 0:
                    B.Merge(x,y,++cnt);
                    break;
                case 1:
                    ans=B.Solve(x,y);
                    Wl(ans);
                    break;
                default:
                    break;
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    C#单例模式的实现再回顾
    智慧质证使用过程中的4个接口
    Amortized Analysis 均摊分析
    668. Kth Smallest Number in Multiplication Table
    1201. Ugly Number III
    1482. Minimum Number of Days to Make m Bouquets
    744. Find Smallest Letter Greater Than Target
    436. Find Right Interval
    50. Pow(x, n)
    29. Divide Two Integers
  • 原文地址:https://www.cnblogs.com/gaojunonly1/p/10402762.html
Copyright © 2011-2022 走看看