POJ2371 问题与答案
首先给出一 个N,一下N行接着给N个数,然后是一个K,接着是K行查询,要问这N个数从小到大的第i个数是多少?
输入:1<=N<=100000,以后每个数1<=X<=5000;查询1<=K<=100,以后每个查询1<=Y<=N。
输出:按照每个查询一次输出第i个数。
分析:由于N有10万个如果用快排排序之后(花费O(nlogn)时间),然后对于每个查询用O(1)时间输出的话,总复杂度就是O(nlogn)。如果用计数排序(由于每个数最多是5000)在O(n)时间里读入并排好每个数,然后对于100个查询每个查询要扫描一遍5000规模的数组,则共最多50万次计算,而用快排要大于1000万次计算。
首先用快排看下程序速度多快:47MS,且用了564K的内存
代码:
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=100000+100;
int n,a[maxn],k;
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
}
sort(a,a+n);
char s[100];
scanf("%s",s);
//printf("%s\n",s);
scanf("%d",&k);
while(k--)
{
int x;
scanf("%d",&x);
printf("%d\n",a[x-1]);
}
return 0;
}
现在看下第二种计数排序方法多快:47MS,192K内存。第二种方法更优
代码:
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=5000+100;
int n,a[maxn],k;//a[x]==y,表示数值为X的这个数出现了y次
int main()
{
scanf("%d",&n);
memset(a,0,sizeof(a));
for(int i=0;i<n;i++)
{
int x;scanf("%d",&x);
a[x]++;
}
char s[100];
scanf("%s",s);
scanf("%d",&k);
while(k--)
{
int x,cnt=0;
scanf("%d",&x);
for(int i=0;i<maxn;i++)
{
cnt+=a[i];
if(cnt>=x)
{
printf("%d\n",i);
break;
}
}
}
return 0;
}