洛谷月赛P9497题解

个人认为这题是整个比赛中最简单的。。。

但是,分治的光芒无处不在,所以,我们先来看一下50分的代码(实在看不懂,那10分是给谁的)。。。

50分的代码就是暴力,思路就是统计全表中一共有多少元素大于v,如果大于n,那么就输出n,否则就输出数量。

时间复杂度:$O(n^2q)$

*TLECode:*
```c++
#include<iostream>
#include<cstdio>
#include<algorithm>
#define int long long
using namespace std;
int board[1005][1005];
int n,q;
int w;
signed main(){
    scanf("%lld%lld",&n,&q);
    for(int i = 0;i < n;i++){
        for(int j = 0;j < n;j++){
            scanf("%lld",&board[i][j]);
        }
    }
    while(q--){
        scanf("%lld",&w);
        int cnt=0;
        for(int i = 0;i < n;i++){
            for(int j = 0;j < n;j++){
                if(board[i][j]>=w) cnt++;
            }
        }
        printf("%lld\n",min(cnt,n));
    }
    return 0;
}
```

到这里,我们就可以拿到50分。

然后,我们看到29道34行

我们想,cnt达到n了就直接输出不就行了,为什么还有继续统计下去呢?

所以就有了以下代码

*TLECode:*
```c++
#include<iostream>
#include<cstdio>
#define int long long
using namespace std;
int board[1005][1005];
int n,q;
int w;
signed main(){
    scanf("%lld%lld",&n,&q);
    for(int i = 0;i < n;i++){
        for(int j = 0;j < n;j++){
            scanf("%lld",&board[i][j]);
        }
    }
    while(q--){
        scanf("%lld",&w);
        int cnt=0;
        for(int i = 0;i < n;i++){
            for(int j = 0;j < n;j++){
                if(board[i][j]>=w) cnt++;
                if(cnt>=n){
                    printf("%lld\n",n);
                    goto s;
                }
            }
        }
        printf("%lld\n",cnt);
s:
;
    }
    return 0;
}
```
还是50分,不过稍微快了一点。

那我们就想,怎么才能快一点,达到$O(n log n)$时间复杂的呢?

我们再看一遍刚才的代码,我们发现,这是顺序统计,那么我们可以二分,从而达到$O(n log n)$ 时间复杂度
还有,因为快排最差情况会退化至$O(n^2)$,所以,我不放心,就收写了一个归并排序。

*ACCode:*

```c++
#include<iostream>
#include<algorithm>
#include<cstdio>
#define int long long
using namespace std;
int n,q,v;
int a[1000005];
int b[1000005];
void msort(int l,int r){
    if(l==r) return;
    int mid=(l+r)/2;
    msort(l,mid);
    msort(mid+1,r);
    int i=l,j=mid+1,k=l;
    while(i<=mid and j<=r){
        if(a[i]<=a[j]){
            b[k++]=a[i++];
        }else{
            b[k++]=a[j++];
        }
    }
    while(j<=r) b[k++]=a[j++];
    while(i<=mid) b[k++]=a[i++];
    for(int z = l;z <= r;z++){
        a[z]=b[z];
    }
    return;
}
signed main(){
    scanf("%lld%lld",&n,&q);
    for(int i = 0;i < n*n;i++){
        scanf("%lld",&a[i]);
    }
    msort(0,n*n-1);
    while(q--){
        scanf("%lld",&v);
        if(v>a[n*n-1]){
            printf("0\n");
            continue;
        }
        int up=lower_bound(a,a+n*n,v)-a;
        int ans=(n*n)-up;
        if(ans>=n){
            printf("%lld\n",n);
        }else{
            printf("%lld\n",ans);
        }
    }
    return 0;
}
```
拒绝抄袭题解,洛谷明天更好!

管理求过。qwq

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值