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('\n')
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('\n')
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('\n')
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('\n')
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

 

posted @ 2019-02-19 18:15  yccdu  阅读(158)  评论(0编辑  收藏  举报