有序数列第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