497 div1 A sorting two pointers 1300

原文题目
You are given an array of integers. Vasya can permute (change order) its integers. He wants to do it so that as many as possible integers will become on a place where a smaller integer used to stand. Help Vasya find the maximal number of such integers.

For instance, if we are given an array [10,20,30,40], we can permute it so that it becomes [20,40,10,30]. Then on the first and the second positions the integers became larger (20>10, 40>20) and did not on the third and the fourth, so for this permutation, the number that Vasya wants to maximize equals 2. Read the note for the first example, there is one more demonstrative test case.

Help Vasya to permute integers in such way that the number of positions in a new array, where integers are greater than in the original one, is maximal.

Input
The first line contains a single integer n (1≤n≤105) — the length of the array.

The second line contains n integers a1,a2,…,an (1≤ai≤109) — the elements of the array.

Output
Print a single integer — the maximal number of the array’s elements which after a permutation will stand on the position where a smaller element stood in the initial array.

中文题意
给了一个数组,要求将数组重新排列后,有多少个位置上的新的数字大于旧的数字

题解
题目要求的是大于原来的数的数目,那么本质上就是找一个数大于原来的数,问能找到多少个。
因为一个数在被找到之后就不能用了,所以我们可以很容易想到极限情况,就是刚刚好比这个数大,也就是离这个数最近的大于它的数。
因为是找,如果是传统的O(n^2)暴力枚举一定会超时,所以为了降低时间成本,我们可以采用二分查找:
如果当前的数比原来的数大,而且当前的数没有被使用过,那么就记录当前的数,然后向左找(为了找到刚刚好大于它的数)
否则就向右找
注意,每一次找到一个符合条件的mid后都要保存下来,因为我们要取的是最优情况的mid,也就是每次如果能找到,就只标记最优的,对于剩下的我们可以用给别的数。
但是,我们也要给原来的数组排序,这样如果找到的mid是用过的,那么就直接向右找就可以了,这是类似贪心的思想,如果这个数被用了,说明它满足了一个恰好的最大值,那么小于它的数一定也满足被用了,或者就并不适用,所以我们需要向右找就可了

#include <bits/stdc++.h>
using namespace std;
int a[100005];
int b[100005];
int c[100005];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n,i,j,k,t,s;
    cin>>n;
    for(i=0;i<n;i++){
        cin>>a[i];
        b[i]=a[i];
    }
    int mid;
    sort(a,a+n);
    sort(b,b+n);
    t=0;
    bool flag;
    j=-1;
    for(i=0;i<n;i++){
        flag=0;
        s=b[i];
        int l=0;
        int r=n-1;
        while(l<=r){
            mid=l+(r-l)/2;
            if(a[mid]>s&&c[mid]==0){
                    j=mid;
                    flag=1;
                    r=mid-1;
            }
            else l=mid+1;
        }
        if(flag==1)
        {
        t++;
        c[j]=1;
        //cout<<j<<" "<<i<<endl;
        }
    }
    cout<<t<<endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值