题目链接 微软大楼设计方案

中文题就不说题意了~

首先是简单版本

满足$1 <= n, m <= 50$

那么设$c[i][j]$为从第$i$幢楼到第$j$幢楼的最低的那幢楼的高度

计算两个点之间的距离的时候,若两个点分别在第$i$列,第$j$列,那么要根据$c[i][j]$来计算。

暴力即可

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i) int n, k;
int a[10010];
int c[201][201];
int x[201], y[201];
int m;
int ans = 0; int main(){ scanf("%d%d", &n, &k);
rep(i, 1, n) scanf("%d", a + i);
rep(i, 1, n){
c[i][i] = a[i];
rep(j, i + 1, n) c[i][j] = min(c[i][j - 1], a[j]), c[j][i] = c[i][j];
} rep(i, 1, n) rep(j, 1, n) if (c[i][j] == 0) c[i][j] = c[j][i]; scanf("%d", &m); rep(i, 1, m) scanf("%d%d", x + i, y + i); rep(i, 1, m - 1){
rep(j, i + 1, m){
int cnt;
if (y[i] > c[x[i]][x[j]] && y[j] > c[x[i]][x[j]])
cnt = y[i] - c[x[i]][x[j]] + y[j] - c[x[i]][x[j]] + abs(x[i] - x[j]);
else cnt = abs(x[i] - x[j]) + abs(y[i] - y[j]);
if (cnt <= k) ++ans;
}
} printf("%d\n", ans);
return 0; }

再是中等版本

满足$1 <= n <= 200000, 1 <= m <= 2000$

$m$的范围让我们还是可以在1秒钟之内两两枚举点对并完成统计

就是$c[i][j]$不能按照刚刚那个方法求了。

我们构建一张ST表,令$f[i][j]$为从$i$开始连续$2^{j}$个数的最小值

于是在$O(1)$内我们可以得到第$i$幢楼到第$j$幢楼的最低的那幢楼的高度

中等版本也解决了

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i) int a[200030];
int f[200030][22];
int n, m, k;
int ans = 0; struct node{
int x, y;
void scan(){ scanf("%d%d", &x, &y);}
friend bool operator < (const node &a, const node &b){
return a.x == b.x ? a.y < b.y : a.x < b.x;
}
} p[3010]; inline int solve(int l, int r){
int k = (int)log2((double)(r - l + 1));
return min(f[l][k], f[r - (1 << k) + 1][k]);
} void work(){
rep(i, 1, n) f[i][0] = a[i];
rep(j, 1, 20) rep(i, 1, n)
if ((i + (1 << j) - 1) <= n) f[i][j] = min(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
} int main(){ scanf("%d%d", &n, &k);
rep(i, 1, n) scanf("%d", a + i); work(); scanf("%d", &m);
rep(i, 1, m) p[i].scan();
sort(p + 1, p + m + 1); rep(i, 1, m - 1){
rep(j, i + 1, m){
int cnt;
int now = solve(p[i].x, p[j].x);
if (p[i].y > now && p[j].y > now)
cnt = p[i].y - now + p[j].y - now + abs(p[i].x - p[j].x);
else cnt = abs(p[i].x - p[j].x) + abs(p[i].y - p[j].y);
if (cnt <= k) ++ans;
}
} printf("%d\n", ans);
return 0; }

最后是困难版本

满足$1 <= n <= 200000, 1 <= m <= 200000$

这个时候不能两两枚举点对来统计了

注意到$h[i] <= 20$,这是一个很重要的条件

对于当前在第$i$列的某个点,我们发现在他之后的$max(0, k - 40)$列中的所有点

这些点不用考虑,一定符合条件

因位距离最大值为$ k - 40 + max(h[i]) + max(h[j]) <= k$,所以一定符合条件

同理我们也发现,第$i + k$之后的点肯定不符合条件

那么我们只要枚举$i + max(0, k - 40) + 1$ 到 $i + k$ 这些列中的所有点就可以了

做的时候维护一个前缀和即可。

时间复杂度$O(mlogm + mh^{2})$

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i) const int N = 200100; int a[N];
int f[N][22];
int n, m, k;
long long ans = 0;
long long c[N];
int g[N][22]; vector <int> v[N]; struct node{
int x, y;
void scan(){ scanf("%d%d", &x, &y);}
friend bool operator < (const node &a, const node &b){
return a.x == b.x ? a.y < b.y : a.x < b.x;
}
} p[N]; inline int solve(int l, int r){
int k = (int)log2((double)(r - l + 1));
return min(f[l][k], f[r - (1 << k) + 1][k]);
} void work(){
rep(i, 1, n) f[i][0] = a[i];
rep(j, 1, 20) rep(i, 1, n)
if ((i + (1 << j) - 1) <= n) f[i][j] = min(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
} int main(){ scanf("%d%d", &n, &k); rep(i, 1, n) scanf("%d", a + i); work(); scanf("%d", &m);
rep(i, 1, m) p[i].scan();
sort(p + 1, p + m + 1);
memset(g, 0, sizeof g); rep(i, 1, m) ++c[p[i].x];
rep(i, 1, n) c[i] += c[i - 1];
rep(i, 1, m){
v[p[i].x].push_back(i);
g[p[i].x][p[i].y] = 1;
} rep(i, 1, m){
rep(j, p[i].y + 1, a[p[i].x]) if (abs(j - p[i].y) <= k && g[p[i].x][j]) ++ans;
int cnt = p[i].x + k - 40;
if (cnt > n) cnt = n; if (cnt > p[i].x){
long long xx = c[cnt], yy = c[p[i].x];
ans += xx - yy;
} int now = p[i].x + k;
if (now > n) now = n; rep(j, max(cnt + 1, p[i].x + 1), now){ for (auto u : v[j]){
int cnt;
int now = solve(p[i].x, p[u].x);
if (p[i].y > now && p[u].y > now)
cnt = p[i].y - now + p[u].y - now + abs(p[i].x - p[u].x);
else cnt = abs(p[i].x - p[u].x) + abs(p[i].y - p[u].y); if (cnt <= k) ++ans; } } } printf("%lld\n", ans);
return 0; }

计蒜客 微软大楼设计方案(RMQ)的更多相关文章

  1. 计蒜课/ 微软大楼设计方案/中等(xjb)

    题目链接:https://nanti.jisuanke.com/t/15772 题意:中文题诶- 思路:对于坐标为p1(x1, y1), p2(x2, y2) 的两个核心, 其中 x1 <= x ...

  2. 计蒜客 作弊揭发者(string的应用)

    鉴于我市拥堵的交通状况,市政交管部门经过听证决定在道路两侧安置自动停车收费系统.当车辆驶入车位,系统会通过配有的摄像头拍摄车辆画面,通过识别车牌上的数字.字母序列识别车牌,通过连接车管所车辆信息数据库 ...

  3. 计蒜客的一道题dfs

    这是我无聊时在计蒜客发现的一道题. 题意: 蒜头君有一天闲来无事和小萌一起玩游戏,游戏的内容是这样的:他们不知道从哪里找到了N根不同长度的木棍, 看谁能猜出这些木棍一共能拼出多少个不同的不等边三角形. ...

  4. 计蒜客模拟赛5 D2T1 成绩统计

    又到了一年一度的新生入学季了,清华和北大的计算机系同学都参加了同一场开学考试(因为两校兄弟情谊深厚嘛,来一场联考还是很正常的). 不幸的是,正当老师要统计大家的成绩时,世界上的所有计算机全部瘫痪了. ...

  5. 计蒜客 等边三角形 dfs

    题目: https://www.jisuanke.com/course/2291/182238 思路: 1.dfs(int a,int b,int c,int index)//a,b,c三条边的边长, ...

  6. 计蒜客 方程的解数 dfs

    题目: https://www.jisuanke.com/course/2291/182237 思路: 来自:https://blog.csdn.net/qq_29980371/article/det ...

  7. 计蒜客 买书 dfs

    题目: https://www.jisuanke.com/course/2291/182236 思路: 递归解决,从第一本书开始,每本书都有两种选择: //index是book里面每本书价格的下标, ...

  8. 计蒜客:Entertainment Box

    Ada, Bertrand and Charles often argue over which TV shows to watch, and to avoid some of their fight ...

  9. 爬虫acm比赛成绩(多页成绩整合在一起、获取复制不了的数据)(hihocoder、计蒜客)

    https://github.com/congmingyige/web-crawler_rank-of-competition-in-JiSuanKe-and-hihocoder 1. 计蒜客(获取复 ...

随机推荐

  1. destoon修改手机端分页

    1. global.func.php pages函数和listpages函数 函数开头增加 $DT_TOUCH,$newsamplepages变量 global $DT_URL, $DT, $L,$D ...

  2. 《linux设备驱动开发详解》笔记——14 linux网络设备驱动

    14.1 网络设备驱动结构 网络协议接口层:硬件无关,标准收发函数dev_queue_xmit()和netif_rx();  注意,netif_rx是将接收到的数据给上层,有时也在驱动收到数据以后调用 ...

  3. PTA 7-1 银行业务队列简单模拟

    用链表实现队列操作,代码如下: #include <iostream> #include <cstdio> #include <algorithm> #includ ...

  4. Linux压缩与归档

    文件的压缩     aaaaaabbbbccc压缩成为6a4b3c     压缩工具:     gzip/gunzip: .gz后缀         只能压缩文件,不能压缩目录,因其不具备归档功能   ...

  5. luogu2766 最长不下降子序列问题

    第一问DP水过.dp[i]代表以i结尾的最长不下降子序列长度. 二三问网络流. 第二问是说每个子序列不能重复使用某个数字. 把每个点拆成p(i),q(i).连边. 要是dp[i]=1,连源,p(i) ...

  6. 前端PS切图技巧

    先选择“编辑”-“首选项” 打开,找到“参考线”    设置一下每格网格 100像素 5个细块 确定后 ctrl+‘ 出现网格.(通过网格对齐切图比用参考线切图更好). 如果使用PS cc的软件的话, ...

  7. 【java基础 12】HashMap中是如何形成环形链表的?

    导读:经过前面的博客总结,可以知道的是,HashMap是有一个一维数组和一个链表组成,从而得知,在解决冲突问题时,hashmap选择的是链地址法.为什么HashMap会用一个数组这链表组成,当时给出的 ...

  8. js 抓取页面数据

    数据抓取 主要思路和原理 在根节点document中监听所有需要抓取的事件 在元素事件传递中,捕获阶段获取事件信息,进行埋点 通过getBoundingClientRect() 方法可获取元素的大小和 ...

  9. 数据表自动生成java代码

    MyBatis生成代码需要用到mybatis-generator-core-1.3.2.jar.数据库连接驱动包和一个xml文件,xml文件一般命令为:generator.xml. Xml内容格式如下 ...

  10. 【bzoj3261】最大异或和 可持久化Trie树

    题目描述 给定一个非负整数序列 {a},初始长度为 N.       有M个操作,有以下两种操作类型:1.A x:添加操作,表示在序列末尾添加一个数 x,序列的长度 N+1.2.Q l r x:询问操 ...