离散化

本人水平有限,题解不到为处,请多多谅解

本蒟蒻谢谢大家观看

题目:      

            Problem A: ycz的离散化

Description

给你n个数,每个数的大小在long long范围内。
请输出n个数升序排序(小的在前,大的在后)后,第k个数的排名

Input

第一行两个数n,k,n<=5e5,k<=n
第二行n个数,每个数的权值在[0,1e15]之间

Output

输出一行一个整数,代表第k个数在升序排序之后的排名

Sample Input

7 6
1 8 8 3 2 -5 6

Sample Output

1

HINT

解析:https://www.cnblogs.com/cytus/p/8933597.html

法一:code:

#include<bits/stdc++.h>
#pragma GCC optimize(3)
#define int long long
#define fill(a,b) memset(a,b,sizeof(a))
using namespace std;
int k,n,a[500010],t[500010],rank[500010],m;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;
}
signed main(){
    n=read(),k=read();
    for (int i=1;i<=n;i++){
        a[i]=read();
        t[i]=a[i];
    }
    sort(t+1,t+n+1);
    m=unique(t+1,t+n+1)-t-1;
    for (int i=1;i<=n;i++)
        a[i]=lower_bound(t+1,t+m+1,a[i])-t;
    printf("%lld",a[k]);
    return 0;
}

 在这段代码中,a[]经过离散,范围就变成了m。解释一下,unique是c++自带的一个函数,表示对一个数列去重,然后返回不重复的元素个数,当然在后面要减去首地址(t+1)。那么这种离散化对于有重复元素的数列也可以适用,但复杂度相对后面要讲的第二种方法会高些。

  举个栗子

  {6,8,4,9,5,6,7,4},首先排序后得到{4,4,5,6,6,7,8,9},去重{4,5,6,7,8,9},然后原序列就变成了 离散(相当于存储从小到大的位置

       {3,5,1,6,2,3,4,1}。

lower_bound( )upper_bound( )都是利用二分查找的方法在一个排好序的数组中进行查找的。在从小到大的排序数组中,lower_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。

upper_bound()只是找第一个大于num的数字

所以此题还可以写成:a[i]=upper_bound(t+1,t+m+1,a[i])-t;

输出:a[k]-1 即可

法二:code:

#include<bits/stdc++.h>
#pragma GCC optimize(3)
#define int long long
using namespace std;
int k,n,t[500010],rank1[500010],m,ans,cnt;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;
}
struct node{
  int v,id;
}a[500010];
bool cmp(node a,node b){
    return a.v<b.v;
}
signed main()
{
  n=read(),k=read();
  for(int i=1;i<=n;i++){
    a[i].v=read();
    a[i].id=i;
   }
  sort(a+1,a+n+1,cmp);
  //int m=unique(t+1,t+n+1)-t-1;
  cnt=0;
  a[0].v=1ll*1e16;//要给a[0].v赋初值,否则当a[1].v==a[0].v==0时,直接输出0,WA了
    for(int i=1;i<=n;i++){
    if(a[i].v!=a[i-1].v){
        cnt++;
    }
    rank1[a[i].id]=cnt;
  }
  // for(int i=1;i<=n;i++)
  //      cout<<rank1[i]<<" ";
  //  cout<<endl;
    printf("%lld
",rank1[k]);
    return 0;
}
/*
7 6
1 8 8 3 2 -5 6

8 3
1 8 8 3 3 2 -5 6
*/

如果不赋a[0].v初值,一组hank数据

9 7
1 8 8 3 3 2 0 0 6

正确答案应为1

不赋a[0].v初值的WA答案为0

此方法类似于

NOIP2013火柴排队

         来自于我的博客   

    欢迎大家阅读归并排序之逆序对   

 逃~

 
原文地址:https://www.cnblogs.com/nlyzl/p/11536644.html