b_lq_小明的魔法(反向思维)

给定小明的城堡图(小明的城堡并不是平面的,而是立体的)
请问,水的高度依次为 1,2,3,....,H时,有多少块积木要被水淹。
对于所有评测用例,\(1<=n,m<=1000,1<=H<=100000\),积木层数不超过\(10^9\)

思路
27/30做法:优化暴力即不去将枚举H的放在最外层循环,而是枚举h的在最内层,然后结束条件为min(g[i][j], h),这样可提早结束循环;
29/30做法:将二维网格转为一维,然后降序排序,对于每一个高度h,都从后往前找≥h的积木高度的方格个数,累加到s中

#include<bits/stdc++.h>
using namespace std;
int n,m,a[1005*1005];
int main() {
    int p=0; scanf("%d%d", &n,&m);
    for (int i=0; i<n; i++)
    for (int j=0; j<m; j++) 
        scanf("%d", &a[p++]);
    int h, N=n*m, H, s=0; cin>>H;
    sort(a,a+p,[&](int a, int b) {return b>a;});
    for (int h=1; h<=H; h++) {
        int i=p-1;
        while (i>=0 && a[i]>=h) i--;
        s+=p-i-1;
        printf("%d\n", s);
    }
    return 0;
}

30/30的做法是:升序排序数组a,这样就不用每次都从p-1开始枚举

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m,a[1005*1005];
int main() {
    int p=0; scanf("%d%d", &n,&m);
    for (int i=0; i<n; i++)
    for (int j=0; j<m; j++) 
        scanf("%d", &a[p++]);
    ll h, N=n*m, H, i=0, last=0; cin>>H;
    sort(a,a+p);
    for (ll h=1; h<=H; h++) {
        while (i<p && a[i]<h) i++;
        last+=N-i;      //筛选出已经淹没过的积木的个数i,N-i就是当前高度h可淹没的积木个数
        printf("%lld\n", last);
    }
    return 0;
}
posted @ 2020-10-12 21:33  童年の波鞋  阅读(64)  评论(0编辑  收藏  举报