牛客多校H题题解
链接:[https://ac.nowcoder.com/acm/contest/81597/H]
来源:牛客网
题目描述
Red stands at the coordinate \((0,0)\) of the Cartesian coordinate system. She has a string of instructions: up, down, left, right (where 'right' increases the x-coordinate by \(1\), and 'up' increases the y-coordinate by \(1\)).Now Red wants to select a continuous substring of instructions and execute them. Red hopes that the final execution of the instructions can pass through the coordinate \((x,y)\). She wants to know how many selection options there are.
输入描述:
The first line contains three integers \(n\), \(x\), and \(y\) ( \(1≤n≤2×10^5\),\(−10^5≤,≤10^5\))(\(1≤n≤2×10^5\),\(−10^5≤x,y≤10^ 5\)), —the length of the instruction string and the coordinates Red hopes to pass through.
The second line contains a string of length n, consisting of the characters '\(W\)', '\(S\)', '\(A\)', and '\(D\)'. — the four directions: up, down, left, and right, respectively.
输出描述:
Output one integer representing the number of selection options for the continuous substring.
解题大概思路
该题目我们想的暴力思路大概就是通过构建两个前缀和数组来,每次通过哈希表查找前缀和与目标\(x\) (或者\(y\))的对应的前缀和是否存在,如果存在,就把该区间存入区间另外一个哈希表内.这一部分的时间复杂度为\(O(nlog(n))\)级别
然后跑了一遍\(O(n)\)循环之后,再遍历一遍存储着符合条件的区间的哈希表,从哈希表里面选出符合要求的区间,这里特别要注意统计区间的时候要考虑清楚,避免重复统计区间
代码处理:
特殊判定 起点为(0,0)的情况下:
if(!x && !y) {
cout << n * (n + 1) / 2 << nn;
return;
}
初始化哈希表,记录出现过的区间
mp[{0, 0}].push_back(0);
set<pair<int, int>> se;
初始化前缀和数组
sx[i] = sx[i - 1] + dx[s[i]];
sy[i] = sy[i - 1] + dy[s[i]];
每次插入一个二维前缀和的时候,通过\(map\) 用\(O(log(n))\) 的时间复杂度来进行查询是否查找到了所需要的区间
像我比赛时写的代码进行了三次哈希查找,其中有一个哈希查找还相互嵌套,时间复杂度大概是\(O((log(n))^2)\)所以TLE了
auto v = mp[{sx[i] - x, sy[i] - y}];
//取出 右边的下标
if(!v.empty()) {
//如果找到了对应的一个前缀和
for(auto l: v) {
// if(l == i) se.insert({l, i});
if(l + 1 <= i) se.insert({l + 1, i});
//前面的if判断其实很多余
}
}
最后再在大的set里面找出所需要的区间
其实这里就算不用位图去重也可以的,因为此时哈希表里面的区间都是满足题目意思的区间
所以这里我感觉直接输出
se.size()就是最佳答案
for(auto x: se) {
int l = x.first, r = x.second;
if(vis[l]) continue;
vis[l] = 1;
ans += n - r + 1;
//如果有效就加上 n-r+1
}
AC code:
#include<bits/stdc++.h>
#define int long long
#define nn '\n'
using namespace std;
const int maxn = 2e5 + 5;
int sx[maxn], sy[maxn]; // 位置从1开始
bitset<maxn> vis;
void solve() {
int n, x, y, ans = 0;
string s;
cin >> n >> x >> y >> s;
if(!x && !y) {
cout << n * (n + 1) / 2 << nn;
return;
}
//特殊判定 起点为(0,0)的情况下
s = '0' + s;
map<char, int> dx, dy;
dx['D'] = 1, dx['A'] = -1;
dy['W'] = 1, dy['S'] = -1;
map<pair<int, int>, vector<int>> mp;
//初始化哈希表,记录出现过的区间
mp[{0, 0}].push_back(0);
set<pair<int, int>> se;
for(int i = 1; i <= n; i++) {
sx[i] = sx[i - 1] + dx[s[i]];
sy[i] = sy[i - 1] + dy[s[i]];
//初始化前缀和数组
mp[{sx[i], sy[i]}].push_back(i);
//直接这样插入元素???
auto v = mp[{sx[i] - x, sy[i] - y}];
//取出 右边的下标
if(!v.empty()) {
//如果找到了对应的一个前缀和
for(auto l: v) {
// if(l == i) se.insert({l, i});
if(l + 1 <= i) se.insert({l + 1, i});
//前面的if判断其实很多余
}
}
}
// for(auto x: se) {
// cout << x.first << ' ' << x.second << nn;
// }
set<string> ss;
//然后现在要对存入区间内的有效区间0进行判断
for(auto x: se) {
int l = x.first, r = x.second;
if(vis[l]) continue;
vis[l] = 1;
ans += n - r + 1;
//如果有效就加上 n-r+1
}
cout << ans << nn;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int _ = 1;
// cin >> _;
while(_--)
solve();
return 0;
}
这里附上一篇大佬的代码,简洁优雅简直让人拜服!
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n, a, b, ans;
char c;
pair<int, int> m[1000005];
map<pair<int, int>, int> t;
signed main()
{
cin >> n >> a >> b;
if (a == 0 && b == 0) {
cout << n * (n + 1) / 2;
return 0;
}
for (int i = 1; i <= n; i++) {
cin >> c;
if (c == 'A') m[i] = {m[i - 1].first - 1, m[i - 1].second + 0};
if (c == 'S') m[i] = {m[i - 1].first + 0, m[i - 1].second - 1};
if (c == 'W') m[i] = {m[i - 1].first + 0, m[i - 1].second + 1};
if (c == 'D') m[i] = {m[i - 1].first + 1, m[i - 1].second + 0};
}
for (int i = n; i > 0; i--) {
t[{m[i].first - a, m[i].second - b}] = n - i + 1;
ans += t[{m[i - 1].first, m[i - 1].second}];
}
cout <<br ans;
return 0;
}
那么这段AC代码到底包含着什么样的逻辑呢??
1.首先通过设置前缀和来统计各个前缀字符串到达的位置
2.反向进行遍历,如果此时map里面存在元素,那么map内包含的也就是n-i+1(后面计算过的),如果不存在,就是0;
那为什么要反向排列呢?因为反向排列是从后面的元素开始逆推,如果是正向开始,貌似也行哦,只需要重复该步骤就可以了,这里的处理是真的优雅!!!!
牛客多校H题题解的更多相关文章
- 数位dp——牛客多校H
/* x[1,A] y[1,B] x^y<C 或 x&y>C 把ABC拆成二进制后按位进行数位dp dp[pos][s1][s2][f1][f2] 表示从高到低第pos位,条件一状 ...
- LGV算法 CodeForces 348D + 牛客多校 A Monotonic Matrix
定理(Lindström–Gessel–Viennot lemma)很简单: 学的时候忘了大的行列式怎么算的了.. 然后就可以写题了: 第一道:CodeForces-348D(链接https://vj ...
- 2020牛客多校第八场K题
__int128(例题:2020牛客多校第八场K题) 题意: 有n道菜,第i道菜的利润为\(a_i\),且有\(b_i\)盘.你要按照下列要求给顾客上菜. 1.每位顾客至少有一道菜 2.给顾客上菜时, ...
- 2019牛客多校第八场 F题 Flowers 计算几何+线段树
2019牛客多校第八场 F题 Flowers 先枚举出三角形内部的点D. 下面所说的旋转没有指明逆时针还是顺时针则是指逆时针旋转. 固定内部点的答案的获取 anti(A)anti(A)anti(A)或 ...
- 2019年牛客多校第一场B题Integration 数学
2019年牛客多校第一场B题 Integration 题意 给出一个公式,求值 思路 明显的化简公式题,公式是分母连乘形式,这个时候要想到拆分,那如何拆分母呢,自然是裂项,此时有很多项裂项,我们不妨从 ...
- 2019牛客多校 Round4
Solved:3 Rank:331 B xor 题意:5e4个集合 每个集合最多32个数 5e4个询问 询问l到r个集合是不是都有一个子集的xor和等于x 题解:在牛客多校第一场学了线性基 然后这个题 ...
- 牛客多校第3场 J 思维+树状数组+二分
牛客多校第3场 J 思维+树状数组+二分 传送门:https://ac.nowcoder.com/acm/contest/883/J 题意: 给你q个询问,和一个队列容量f 询问有两种操作: 0.访问 ...
- 牛客网Java刷题知识点之HashMap的实现原理、HashMap的存储结构、HashMap在JDK1.6、JDK1.7、JDK1.8之间的差异以及带来的性能影响
不多说,直接上干货! 福利 => 每天都推送 欢迎大家,关注微信扫码并加入我的4个微信公众号: 大数据躺过的坑 Java从入门到架构师 人工智能躺过的坑 ...
- 2019牛客多校第一场 I Points Division(动态规划+线段树)
2019牛客多校第一场 I Points Division(动态规划+线段树) 传送门:https://ac.nowcoder.com/acm/contest/881/I 题意: 给你n个点,每个点有 ...
- 牛客多校第一场 B Inergratiion
牛客多校第一场 B Inergratiion 传送门:https://ac.nowcoder.com/acm/contest/881/B 题意: 给你一个 [求值为多少 题解: 根据线代的知识 我们可 ...
随机推荐
- Java常用类——包装类 小白版个人推荐
包装类及自动装箱/拆箱 包装类是将Java中的八种基本数据类型封装成的类,所有数据类型都能很方便地与对应的包装类相互转换,以解决应用中要求使用数据类型,而不能使用基本数据类型的情况. int a = ...
- 使用 setResponseStatus 函数设置响应状态码
title: 使用 setResponseStatus 函数设置响应状态码 date: 2024/8/25 updated: 2024/8/25 author: cmdragon excerpt: 通 ...
- Homebrew 使用
使用 brew install brew uninstall|remove|rm brew list # *显示已安装软件列表 brew upgrade # 更新 Homebrew brew sear ...
- manim边学边做--曲线类
manim中曲线,除了前面介绍的圆弧类曲线,也可以绘制任意的曲线. manim中提供的CubicBezier模块,可以利用三次贝塞尔曲线的方式绘制任意曲线. 关于贝塞尔曲线的介绍,可以参考:https ...
- 【YashanDB知识库】ycm托管数据库时报错OM host ip:127.0.0.1 is not support join to YCM
问题现象 托管数据库时检查报错OM的IP是127.0.0.1,不支持托管到YCM OM 问题的风险及影响 导致数据库无法托管监控 问题影响的版本 问题发生原因 安装数据库时修改了OM的监听ip为127 ...
- 立体视觉 StereoVision
双目相机 原理 [深度相机系列三]深度相机原理揭秘--双目立体视觉 StereoVision--立体视觉(1) StereoVision--立体视觉(2) StereoVision--立体视觉(3) ...
- Figma 学习笔记 – Layout Grid
前言 我原本以为, 在 Figma 只要用 Auto Layout 就可以打天下. 真的是 too young too simple. 要做一个简单的 7:3 比例, 用 Auto Layout 是做 ...
- Windbg常用命令及分析套路
自己也在使用windbg分析问题,但是属于刚入门所以转发下大神的总结:https://www.cnblogs.com/fj365/p/13295453.html 常用 !threadpool 查看线程 ...
- SpringMVC —— 请求参数(传递json数据)
接收请求中的json数据 注解 json格式(POJO) json数组(POJO) @RequestBody与@RequestParam区别
- 利用 Page Visibility API 优化网页性能与用户体验
在现代 Web 开发中,用户可能会频繁切换标签页,或让网页处于后台运行.为了避免不必要的资源浪费并提升用户体验,合理利用 Page Visibility API 可以在页面不可见时暂停或减少资源的消耗 ...