有序数列第K小

有序数列第K小

题目描述

给出两个长度分别为\(n,m\)的单调非递减数列,求出它们合并后的第\(k\)小值。

输入输出格式

输入格式:

第一行三个数,\(n,m,k\)如题意所述;

第二行\(n\)个数,依次为数列1;

第三行\(m\)个数,依次为数列2;

输出格式:

一个数,表示合并后的第\(k\)小值。

说明

对于所有数据,\(k\le n+mk≤n+m , a_i\le 10^8\),时间限制200ms。


这个题其实考察的是\(logk\)的分治做法

对当前的两个序列,左指针为\(la,lb\),右指针为\(ra,rb\),求当前的第\(k\)小值。

把第\(k\)小值除2,取两个序列之一贡献这么多,得到子问题

注意边界情况


Code:

#include <cstdio>
int min(int x,int y){return x<y?x:y;}
const int N=1000010;
int n,m,k,a[N],b[N];
void divide(int la,int ra,int lb,int rb,int nk)
{
    if(la>ra)
    {
        printf("%d\n",b[lb+nk-1]);
        return;
    }
    if(lb>rb)
    {
        printf("%d\n",a[la+nk-1]);
        return;
    }
    if(nk==1)
    {
        printf("%d\n",min(a[la],b[lb]));
        return;
    }    
    int lk=nk>>1;
    lk=min(lk,min(ra+1-la,rb+1-lb));
    if(a[la+lk-1]<b[lb+lk-1])
        divide(la+lk,ra,lb,rb,nk-lk);
    else
        divide(la,ra,lb+lk,rb,nk-lk);
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++) scanf("%d",a+i);
    for(int i=1;i<=m;i++) scanf("%d",b+i);
    divide(1,n,1,m,k);
    return 0;
}


有序数列第K小加强版

加上多次区间询问


Code:

#include <cstdio>
int min(int x,int y){return x<y?x:y;}
const int N=1000010;
int n,m,q,a[N],b[N];
void divide(int la,int ra,int lb,int rb,int nk)
{
    if(la>ra)
    {
        printf("%d\n",b[lb+nk-1]);
        return;
    }
    if(lb>rb)
    {
        printf("%d\n",a[la+nk-1]);
        return;
    }
    if(nk==1)
    {
        printf("%d\n",min(a[la],b[lb]));
        return;
    }
    int lk=nk>>1;
    lk=min(lk,min(ra+1-la,rb+1-lb));
    if(a[la+lk-1]<b[lb+lk-1])
        divide(la+lk,ra,lb,rb,nk-lk);
    else
        divide(la,ra,lb+lk,rb,nk-lk);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",a+i);
    for(int i=1;i<=m;i++) scanf("%d",b+i);
    scanf("%d",&q);
    int l1,l2,r1,r2,k;
    for(int i=1;i<=q;i++)
    {
        scanf("%d%d%d%d%d",&l1,&r1,&l2,&r2,&k);
        divide(l1,r1,l2,r2,k);
    }
    return 0;
}

2018.7.26

posted @ 2018-07-26 10:00  露迭月  阅读(385)  评论(0编辑  收藏  举报