本人水平有限,题解不到为处,请多多谅解
本蒟蒻谢谢大家观看
题目:
Problem A: ycz的离散化
Description
请输出n个数升序排序(小的在前,大的在后)后,第k个数的排名
Input
第二行n个数,每个数的权值在[0,1e15]之间
Output
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\n",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
此方法类似于
来自于:我的博客
逃~