计蒜客第六场 微软大楼设计方案(困难)

来源:互联网 发布:mac如何安装win 编辑:程序博客网 时间:2024/05/23 22:10

题目链接:

https://nanti.jisuanke.com/t/15773

题解:

先对点按x排序

设Xa<=Xb

当k<=40时,可以用中等难度的方法枚举Xa再枚举Xb,当Xb-Xa>k时不符合条件,并且更大的Xb也不符合条件,所以不接下去枚举Xb。因为楼层高度最高为20所以最多计算20*20次(这里更正一下,应该是20*m次m具体为多少我也不知道,但肯定不超过40,望dalao指教)

k>40时,从枚举Xa,再对Xb进行二分,找到第一个Xb-Xa>=k-40,则在Xa至Xb之间的核心部门到Xa的距离都是<=k的,因为楼层最高为20,然后继续从Xb用开始枚举Xb,一直到Xb-Xa>k为止,同样最多计算20*20次(20*m次)

PS:表达可能不太清楚,请见谅


#include<bits/stdc++.h>using namespace std;#define MAX_N 200005#define inf 0x3f3f3f3f#define LL long long#define uLL unsigned long longconst LL mod = 1e8;const LL INF = 1e18;typedef pair<int, int>P;const double eps = 1e-6;int h[MAX_N];P p[MAX_N];int minsum[MAX_N][20];void init_RMQ(int n){    for(int i=1;i<=n;i++)        minsum[i][0] = h[i];    int k = log2(1.0*n);    for(int j=1;j<=k;j++) {        for(int i=1;i<=n;i++) {            if(i+(1<<j)-1<=n) {                minsum[i][j] = min(minsum[i][j-1], minsum[i+(1<<(j-1))][j-1]);            }        }    }}int getMin(int i,int j){    int k = (int)log2(1.0*(j-i+1));    return min(minsum[i][k], minsum[j-(1<<k)+1][k]);}int main(){    int n, k, m;    cin >> n >> k;    for(int i=1; i<=n; i++) {        scanf("%d", &h[i]);    }    init_RMQ(n);    cin >> m;    for(int i=0; i<m; i++) {        int x, y;        cin >> x >> y;        p[i] = P(x, y);    }    sort(p, p+m);    LL ans = 0;    if(k<=40) {        for(int i=0; i<m; i++) {            for(int j=i+1; j<m; j++) {                if(p[j].first-p[i].first>k)                    break;                int low = min(p[i].second, p[j].second);                low = min(low, getMin(p[i].first, p[i].second));                int tmp = p[i].second + p[j].second - 2*low + abs(p[i].first - p[j].first);                if(tmp <= k)                    ans++;            }        }    }    else {        for(int i=0; i<m; i++) {            int pos = lower_bound(p, p+m, P(p[i].first+k-40, 0)) - p;//p[i+1]-p[pos]之间的点到p[i]的距离都是小于等于k的            ans += (LL)(pos-i-1);            for(int j=pos; j<m; j++) {                if(p[j].first-p[i].first>k)                    break;                int low = min(p[i].second, p[j].second);                low = min(low, getMin(p[i].first, p[j].first));                int tmp = p[i].second + p[j].second - 2*low + abs(p[i].first - p[j].first);                if(tmp <= k)                    ans++;            }        }    }    cout << ans << endl;}



阅读全文
1 0
原创粉丝点击