链接:[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题题解的更多相关文章

  1. 数位dp——牛客多校H

    /* x[1,A] y[1,B] x^y<C 或 x&y>C 把ABC拆成二进制后按位进行数位dp dp[pos][s1][s2][f1][f2] 表示从高到低第pos位,条件一状 ...

  2. LGV算法 CodeForces 348D + 牛客多校 A Monotonic Matrix

    定理(Lindström–Gessel–Viennot lemma)很简单: 学的时候忘了大的行列式怎么算的了.. 然后就可以写题了: 第一道:CodeForces-348D(链接https://vj ...

  3. 2020牛客多校第八场K题

    __int128(例题:2020牛客多校第八场K题) 题意: 有n道菜,第i道菜的利润为\(a_i\),且有\(b_i\)盘.你要按照下列要求给顾客上菜. 1.每位顾客至少有一道菜 2.给顾客上菜时, ...

  4. 2019牛客多校第八场 F题 Flowers 计算几何+线段树

    2019牛客多校第八场 F题 Flowers 先枚举出三角形内部的点D. 下面所说的旋转没有指明逆时针还是顺时针则是指逆时针旋转. 固定内部点的答案的获取 anti(A)anti(A)anti(A)或 ...

  5. 2019年牛客多校第一场B题Integration 数学

    2019年牛客多校第一场B题 Integration 题意 给出一个公式,求值 思路 明显的化简公式题,公式是分母连乘形式,这个时候要想到拆分,那如何拆分母呢,自然是裂项,此时有很多项裂项,我们不妨从 ...

  6. 2019牛客多校 Round4

    Solved:3 Rank:331 B xor 题意:5e4个集合 每个集合最多32个数 5e4个询问 询问l到r个集合是不是都有一个子集的xor和等于x 题解:在牛客多校第一场学了线性基 然后这个题 ...

  7. 牛客多校第3场 J 思维+树状数组+二分

    牛客多校第3场 J 思维+树状数组+二分 传送门:https://ac.nowcoder.com/acm/contest/883/J 题意: 给你q个询问,和一个队列容量f 询问有两种操作: 0.访问 ...

  8. 牛客网Java刷题知识点之HashMap的实现原理、HashMap的存储结构、HashMap在JDK1.6、JDK1.7、JDK1.8之间的差异以及带来的性能影响

    不多说,直接上干货! 福利 => 每天都推送 欢迎大家,关注微信扫码并加入我的4个微信公众号:   大数据躺过的坑      Java从入门到架构师      人工智能躺过的坑          ...

  9. 2019牛客多校第一场 I Points Division(动态规划+线段树)

    2019牛客多校第一场 I Points Division(动态规划+线段树) 传送门:https://ac.nowcoder.com/acm/contest/881/I 题意: 给你n个点,每个点有 ...

  10. 牛客多校第一场 B Inergratiion

    牛客多校第一场 B Inergratiion 传送门:https://ac.nowcoder.com/acm/contest/881/B 题意: 给你一个 [求值为多少 题解: 根据线代的知识 我们可 ...

随机推荐

  1. 在Ubuntu 16.04 LTS服务器上安装FreeRADIUS和Daloradius的方法

    FreeRADIUS 为AAA Radius Linux下开源解决方案,DaloRadius为图形化web管理工具. freeradius一般用来进行账户认证管理,记账管理,常见的电信运营商的宽带账户 ...

  2. 【CMake系列】05-静态库与动态库编译

    在各种项目类型中,可能我们的项目就是一个 库 项目,向其他人提供 我们开发好的 库 (windows下的 dll /lib : linux下的 .a / .so):有时候在一个项目中,我们对部分功能 ...

  3. 基于python的文字转图片工具

    地址 https://hub.docker.com/r/rainsccc/strtoimg 拉取镜像后,可以启动一个容器来运行该应用程序.以下命令会启动容器并将其端口映射到主机上: docker ru ...

  4. Oracle数据库安装与还原

    安装Oracle 11g数据库 安装数据库参考这位大佬的文章:(135条消息) Oracle 11g版本下载及安装超详细教程图解_oracle11g下载_田夜的博客-CSDN博客 非常详细 利用dmp ...

  5. maven 网关应用:[NACOS ConnectException httpPost] currentServerAddr: http://localhost:8848,

    网关应用运行忽然报错:[NACOS ConnectException httpPost] currentServerAddr: http://localhost:8848, 虽然调整了代码逻辑,但是n ...

  6. 使用 nuxi preview 命令预览 Nuxt 应用

    title: 使用 nuxi preview 命令预览 Nuxt 应用 date: 2024/9/8 updated: 2024/9/8 author: cmdragon excerpt: 摘要:本文 ...

  7. 搭建ipv6并发代理池

    声明 本文章中所有内容仅供学习交流,抓包内容.敏感网址.数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除! 学习目标 ounter(l ...

  8. CSS – Sass & SCSS

    前言 CSS 代码多了就不好管理了, 这是它语法先天的不足. Sass 就是加强它语法的, Sass 为 CSS 引入了一些 JS 语言的特性, 比如 variable, function, para ...

  9. QT硬件通讯基础

    QT硬件通讯基础 使用AI技术辅助生成 1 QT与硬件通讯概述 1.1 QT硬件通讯的基本概念 1.1.1 QT硬件通讯的基本概念 QT硬件通讯的基本概念 QT硬件通讯的基本概念 QT作为一种跨平台的 ...

  10. Windows安装Powershell7.x

    事件起因: 由于需要运行一个脚本,但是该脚本是广大网友群众使用Powershell7写的,我自带的是Powershell5,运行过程中总是出现莫名其妙的问题,于是决定将Powershell升级到Pow ...