acwing---牛的学术圈1---二分法+双指针

整体思路:

如果不考虑L次引用原来的文献,这道题考察的就是遍历h,大于等于h的数是否有h个,取最大的h值。那么我们可以先给c数组排个序,此时c数组是降序的,如果c[h-1]>=h,那就说明满足条件,继续遍历下一个h。考虑到可以L次引用原来的文献,那么条件c[h-1]>=h就变为c[h-1]>=h-1 && c[h-1-L]>=h。依次遍历h也可以用二分或者双指针来优化。

二分法思路:

 太久没用二分法了,,二分查找算法模板 - AcWing

代码:

C++:
#include<bits/stdc++.h>
using namespace std;

int N,L;

bool check(int mid,vector<int>& c){
    if(mid-L-1<0){
        if(c[mid-1]>=mid-1){return true;}
        else{return false;}
    }
    if(mid==0){return true;}
    if(c[mid-1]>=mid-1 && c[mid-L-1]>=mid){return true;}
    return false;
}



int main(){
    cin>>N>>L;
    vector<int> c(N,0);
    for(int i=0;i<N;i++){
        scanf("%d",&c[i]);
    }
    sort(c.rbegin(),c.rend());
    //auto max_=max_element(c.begin(),c.end());
    //int temp=*max_;//最大引用次数
    int l=0;
    int r=N;//h的最大可能值,不考虑当前最大引用次数是因为他可能发生变化(L次引用)
    //二分
    while(l<r){
        int mid=(l+r+1)>>1;
        if(check(mid,c)){
            l=mid;
        }
        else{
            r=mid-1;
        }
    }
    cout<<l;
    return 0;
}
python:
import os
import sys
from typing import List
N,L=map(int,input().split())
c=list(map(int,input().split()))
c.sort(reverse=True)

def check(mid:int,c:List[int],L:int) -> bool:
    if mid-L-1<0:
        if c[mid-1]>=mid-1:
            return True
        else:
            return False
    if mid==0:
        return True
    if c[mid-1]>=mid-1 and c[mid-L-1]>=mid:
        return True
    return False

l=0
r=N
while l<r:
    mid=(l+r+1)>>1
    if check(mid,c,L):
        l=mid
    else:
        r=mid-1
print(l)

注意以下四行代码:

from typing import List  #def:...List[int]
N,L=map(int,input().split())  #一行输入两个数字
c=list(map(int,input().split()))  #一行输入一连串数字
c.sort(reverse=True)  #逆序排序

双指针法思路:

找到 c[] 数组中大于h(也就是遍历的i)的最大索引 j,说明 j 之前的论文不用再增加引用次数。如果c[i] >= i - 1 && i - j <= L,也就是前 j 项引用次数都大于等于 i,第 j+1 项到第 i 项的需要增加的引用次数小于等于L,说明这个 i 可行,就把res更新一下(res记录可行的 i)。

代码:

C++:
#include<bits/stdc++.h>
using namespace std;

int N,L;

int main(){
    cin>>N>>L;
    vector<int> c(N+1,0);
    for(int i=1;i<=N;i++){
        scanf("%d",&c[i]);
    }
    int res=0;
    sort(c.rbegin(),c.rend()-1);  //逆序排第1位~第n位

    for(int i=1,j=N;i<=N;i++){
        while(j && c[j]<i){j--;}
        if(c[i]>=i-1 && i-j<=L){res=i;}
    }
    cout<<res;
    return 0;
}
Python:(TLE了)
import os
import sys
from typing import List
N,L=map(int,input().split())
c=list(map(int,input().split()))
res=0
c.sort(reverse=True)
c=[0]+c

for i in range(1,N+1):
    j=N
    while j>0 and c[j]<i:
        j-=1
    if c[i]>=i-1 and i-j<=L:
        res=i
print(res)

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值