8.13 纪中集训 Day13

T1rank

Description

小h和小R正在看之前的期末&三校联考成绩,小R看完成绩之后很伤心,共有n(n<=5*10^6)个学生,第i个学生有一个总成绩Xi(0<=Xi<=10^5),因为他的排名是倒数第k(1<=k<=n)个,于是小R想知道那些成绩比他低(包括成绩和他一样)的同学的成绩,这样能让他没那么伤心。

Input

第一行,n和k,表示有n个学生,小R排倒数第k.
第二行,n个非负整数,表示这n个学生的成绩。

Output

一行,共k个数,从小到大输出。(相同成绩按不同排名算)

Sample Input

5 3
1 1 2 2 3

Sample Output

1 1 2

考场思路/正解

题目意思很简单,就是要排序一下,不过观察数据范围可得,此处用桶排更佳,所以就没了。

Code

#include<cstdio>
#include<algorithm>

int n,k,v,sl,zx,cc;
int book[100010];

int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&v);
        book[v]++;
    }
    for(int i=0;i<=100000;i++)
    {
        cc=sl;
        sl+=book[i];
        if(sl>=k)
        {
            zx=i;
            break;
        }
    }
    for(int i=0;i<zx;i++)
        if(book[i])
            for(int j=1;j<=book[i];j++)
                printf("%d ",i);
    for(int i=cc;i<k;i++)
        printf("%d ",zx);
    return 0;
}

T2seek

Description

俗话说“好命不如好名”,小h准备给他的宠物狗起个新的名字,于是他把一些英文的名字全抄下来了,写成一行长长的字符串,小h觉得一个名字如果是好名字,那么这个名字在这个串中既是前缀,又是后缀,即是这个名字从前面开始可以匹配,从后面开始也可以匹配,例如abc在 abcddabc中既是前缀,也是后缀,而ab就不是,可是长达4*10^5的字符让小h几乎昏过去了,为了给自己的小狗起个好名字,小h向你求救,并且他要求要将所有的好名字的长度都输出来。

Input

一行,要处理的字符串(都是小写字母)。

Output

一行若干个数字,从小到大输出,表示好名字的长度。

Sample Input

abcddabc

Sample Output

3 8

考场思路/正解

很裸的KMP,不需要解释。。

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int len,k,num;
int Next[400040],zx[400040];
char ch[400040];

int main()
{
    scanf("%s",ch+1);
    len=strlen(ch+1);
    for(int i=2;i<=len;i++)
    {
        while(k>0 && ch[k+1]!=ch[i])
            k=Next[k];
        if(ch[k+1]==ch[i])
            k++;
        Next[i]=k;
    }
    k=Next[len];
    while(k>0)
    {
        zx[++num]=k;
        k=Next[k];
    }
    for(int i=num;i>=1;i--)
        printf("%d ",zx[i]);
    printf("%d",len);
    return 0;
}

T3pot

Description

这个假期,小h在自家院子里种了许多花,它们围成了一个圈,从1..n编号(n<=100000),小h 对每盆花都有一个喜好值xi,(-1000<=xi<=1000),小h现在觉得这样一成不变很枯燥,于是他做了m(m<=100000)个改动,每次把第ki盘花改成喜好值为di的花,然后小h要你告诉他,在这个花圈中,连续的最大喜好值是多少。

Input

第一行,n,花盆的数量
第二行,n个数,表示对于每盆花的喜好值。
第三行:m, 改动的次数
以下m行,每行两个数ki 和di 。

Output

M行,每一行对应一个更改,表示连续的最大喜好值,且不能整圈都选。(注意:是在圈上找)

Sample Input

5
3 -2 1 2 -5
4
2 -2
5 -5
2 -4
5 -1

Sample Output

4
4
3
5

考场思路

考试时就打了一个30分的暴力,还行,尽然没有挂掉。

正解

得知正解以后我的泪水掉下来。哇,比我想象中的简单多了。首先环形子段的最大和其实就是在连续子段的最大和and整个子段和减去连续子段最小和中取一个最大值。(这是我不知道的诶。)然后在随便加一个线段树维护一下,考完以后,直接在10分钟内把这题给A了,连编译都没错,考试时没有想到正解,有点可惜。

Code

#include<cstdio>
#include<algorithm>
using namespace std;

int n,m,zx,d;
struct TREE
{
    int l,r;
    int sum;
    int lmin,rmin,smin;
    int lmax,rmax,smax;
}tree[100010*8];

void Update(int k)
{
    tree[k].sum=tree[k*2].sum+tree[k*2+1].sum;
    tree[k].lmin=min(tree[k*2].lmin,tree[k*2].sum+tree[k*2+1].lmin);
    tree[k].rmin=min(tree[k*2+1].rmin,tree[k*2].rmin+tree[k*2+1].sum);
    tree[k].lmax=max(tree[k*2].lmax,tree[k*2].sum+tree[k*2+1].lmax);
    tree[k].rmax=max(tree[k*2+1].rmax,tree[k*2].rmax+tree[k*2+1].sum);
    tree[k].smin=min(tree[k*2].rmin+tree[k*2+1].lmin,min(tree[k*2].smin,tree[k*2+1].smin));
    tree[k].smax=max(tree[k*2].rmax+tree[k*2+1].lmax,max(tree[k*2].smax,tree[k*2+1].smax));
}

void Build(int L,int R,int k)
{
    int Mid=(L+R)/2;
    tree[k].l=L;tree[k].r=R;
    if(L==R)
    {
        scanf("%d",&tree[k].sum);
        tree[k].lmin=tree[k].rmin=tree[k].smin=tree[k].lmax=tree[k].rmax=tree[k].smax=tree[k].sum;
        return;
    }
    Build(L,Mid,k*2);
    Build(Mid+1,R,k*2+1);
    Update(k);
}

void Work(int L,int R,int k)
{
    int Mid=(L+R)/2;
    if(L==R)
    {
        tree[k].sum=tree[k].lmin=tree[k].rmin=tree[k].smin=tree[k].lmax=tree[k].rmax=tree[k].smax=d;
        return;
    }
    if(zx<=Mid)
        Work(L,Mid,k*2);
    if(Mid<zx)
        Work(Mid+1,R,k*2+1);
    Update(k);
}

int main()
{
    scanf("%d",&n);
    Build(1,n,1);
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&zx,&d);
        Work(1,n,1);
        printf("%d
",max(tree[1].smax,tree[1].sum-tree[1].smin));
    }
    return 0;
}

T4游戏节目

Description

有三支队伍,分别是A,B,C。有n个游戏节目,玩第i个游戏,队伍A可以得到的分数是A[i],队伍B可以得到的分数是B[i],队伍C可以得到的分数是C[i]。由于时间有限,可能不是每个节目都能玩,于是节目主持人决定要从n个游戏节目里面挑选至少k个节目出来(被选中的节目不分次序),使得队伍A成为赢家。队伍A能成为赢家的条件是队伍A的总得分要比队伍B的总得分要高,同时也要比队伍C的总得分要高。节目主持人有多少种不同的选取方案?

Input

第一行,两个整数n和k。 

第二行,  n个整数,分别是A[1]、A[2]、A[3]...A[n]。

第三行,  n个整数,分别是B[1]、B[2]、B[3]...B[n]。

第四行,  n个整数,分别是C[1]、C[2]、C[3]...C[n]。

Output

一个整数,表示不同的选取方案数量。

Sample Input

3 2
1 1 2
1 1 1
1 1 1

Sample Output

3
【样例解释】

方案一:选取节目1和节目3。
方案二:选取节目2和节目3。
方案三:选取节目1、节目2、节目3。

Data Constraint

对于40%数据,2 <= n <= 20。

对于100%数据,2 <= n <= 34,  1 <= k <= min(n,7),  1 <=A[i], B[i], C[i]<= 10^9。

考场思路

考试时没管那么多,反正暴力就是对了嘛。

正解

这题好像是用到了折半搜索然后在外加一个树状数组或线段树进行维护.(有点困,就不详说,相信聪明的读者一定可以在行行代码中看出我想说的话。)

Code

#include<cstdio>
#include<algorithm>
#define lowbit(x) x&-x
#define LL long long
#define NAME "show"
using namespace std;

LL n,kk,ans1,ans2,Count,t,zz;
LL a[55],b[55],c[55],tot[2],sz[262160];

struct thm1
{
    LL x,y;
}q[2][131080];

struct thm2
{
    LL x;
    LL xb;
    LL mark;
}zx[262160];

void Open()<%freopen(NAME".in","r",stdin);freopen(NAME".out","w",stdout);%>

void Dfs1(LL x,LL k,LL suma,LL sumb,LL sumc)
{
    if(x==kk)
        return;
    if(suma>sumb && suma>sumc)
        ans2++;
    for(LL i=k;i<=n;i++)
        Dfs1(x+1,i+1,suma+a[i],sumb+b[i],sumc+c[i]);
}

void Dfs2(LL k,LL sumab,LL sumac,LL pd,LL end)
{
    q[pd][++tot[pd]].x=sumab;
    q[pd][tot[pd]].y=sumac;
    for(LL i=k;i<=end;i++)
        Dfs2(i+1,sumab+(a[i]-b[i]),sumac+(a[i]-c[i]),pd,end);
}

void init()
{
    scanf("%lld%lld",&n,&kk);
    for(LL i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    for(LL i=1;i<=n;i++)
        scanf("%lld",&b[i]);
    for(LL i=1;i<=n;i++)
        scanf("%lld",&c[i]);    
}

bool cmp1(thm2 a,thm2 b)
<%return a.x<b.x;%>
bool cmp2(thm1 a,thm1 b)
<%return a.y<b.y;%>
bool cmp3(thm1 a,thm1 b)
<%return a.y>b.y;%>

void Update(LL x)
{
    while(x<=t)
    {
        sz[x]+=1;
        x+=lowbit(x);
    }
}

LL Sum(LL x)
{
    LL sum=0;
    while(x>=1)
    {
        sum+=sz[x];
        x-=lowbit(x);
    }
    return sum;
}

int main()
{
    Open();
    init();
    Dfs1(0,1,0,0,0);
    Dfs2(1,0,0,0,n/2);
    Dfs2(n/2+1,0,0,1,n);
    for(LL i=1;i<=tot[0];i++)
    {
        zx[++Count].x=q[0][i].x;
        zx[Count].xb=i;
        zx[Count].mark=0;
    }
    for(LL i=1;i<=tot[1];i++)
    {
        zx[++Count].x=-q[1][i].x;
        zx[Count].xb=i;
        zx[Count].mark=1;
    }
    sort(zx+1,zx+1+Count,cmp1);
    zx[0].x=-1e18;
    for(LL i=1;i<=Count;i++)
    {
        if(zx[i].x!=zx[i-1].x)
            t++;
        q[zx[i].mark][zx[i].xb].x=t;
    }    
    sort(q[0]+1,q[0]+1+tot[0],cmp2);
    sort(q[1]+1,q[1]+1+tot[1],cmp3);
    zz=1;
    for(LL i=1;i<=tot[0];i++)
    {
        while(zz<=tot[1] && q[0][i].y+q[1][zz].y>0)
        {
            Update(q[1][zz].x);
            zz++;
        }
        ans1+=Sum(q[0][i].x-1);
    }
    printf("%lld",ans1-ans2);
    return 0;
}

总结

今天其实还不错的吧,至少暴力都没错,明天继续加油吧!

距 NOIp2019 还剩 87 天         祭

原文地址:https://www.cnblogs.com/Thm-V/p/11360769.html