有序数列第K小
题目描述
给出两个长度分别为(n,m)的单调非递减数列,求出它们合并后的第(k)小值。
输入输出格式
输入格式:
第一行三个数,(n,m,k)如题意所述;
第二行(n)个数,依次为数列1;
第三行(m)个数,依次为数列2;
输出格式:
一个数,表示合并后的第(k)小值。
说明
对于所有数据,(kle n+mk≤n+m , a_ile 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
",b[lb+nk-1]);
return;
}
if(lb>rb)
{
printf("%d
",a[la+nk-1]);
return;
}
if(nk==1)
{
printf("%d
",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
",b[lb+nk-1]);
return;
}
if(lb>rb)
{
printf("%d
",a[la+nk-1]);
return;
}
if(nk==1)
{
printf("%d
",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