CF1902D 题解
前言
STL。虽然但是比大数据结构强喵。
题意
有一个无限的平面直角坐标系。最初,机器人站在点 \((0,0)\)。机器人可以执行上下左右四种指令。给定指令序列,每次询问要求翻转指令序列的某个指定子串,问是否经过指定点。
思路
我们考虑把上下左右分别看成 \(({\color{red}0},{\color{blue}+1}),({\color{red}0},{\color{blue}-1}),({\color{red}-1},{\color{blue}0}),({\color{red}+1},{\color{blue}0})\)。我们设映射下来的数组分别为 \({\color{red}a}\) 数组和 \({\color{blue}b}\) 数组,那么这两个数组的前缀和构成的每一个数对就是在不翻转的情况下机器人所能到的 \(({\color{red}x},{\color{blue}y})\)。
现在我们考虑翻转,那么我们就要考虑翻转后的前缀和,也就是考虑后缀和。我们以横坐标 \({\color{red}x}\) 为例,设 \({\color{red}a}\) 的前缀和数组为 \({\color{red}f}\),后缀和数组为 \({\color{red}g}\)。我们考虑翻转区间 \([l,r]\) 对
前缀和数组的影响。
我们发现,翻转区间 \([l,r]\),对 \([1,l-1]\) 和 \([r+1,n]\) 的前缀和是没有影响的,所以我们只考虑翻转区间 \([l,r]\) 对 \([l,r]\) 的前缀和的影响。我们先考虑特殊情况,再考虑一般情况:
- 考虑 \(l=1,r=n\) 时,\(f'_{i}=g_{n-i+1}\),把一个序列翻转,后缀和变成前缀和,这个是显然的。
- 考虑 \(l=1\) 时,\(f'_{i}=g_{{\color{pink}r}-i+1}-g_{r+1}\),因为当我们将 \(r\) 后面的所有元素删除就转化为了上一种情况,此时所有 \(i\le r\) 的 \(g_{i}\) 就都需要减去 \(g_{r+1}\)。注意经过转化后,粉色部分是 \(r\) 而不是 \(n\)。
- 考虑一般情况,则我们的上一个式子相当于将 \(l\) 前面的所有元素删去,那么 \(f'_{i}\) 就比实际少 \(f'_{l-1}\),而根据我们刚才的结论,\(f'_{l-1}=f_{l-1}\),所以 \(f'_{i}=g_{r-i+{\color{pink}l}}-g_{r+1}+f_{l-1}\)。注意经过转化后,粉色部分是 \(l\) 而不是 \(1\)。
所以当 \(i\in [l,r]\) 时,\(f'_{i}=g_{r-i+l}-g_{r+1}+f_{l-1}\)。
当然 \(\color{blue}b\) 数组前后缀的翻转方式与此相同。
那么我们如果要在 \(f'\) 数组里找一个数 \(X\) 时,我们分两种情况讨论:
- \(X\) 不在 \([l,r]\) 内。此时我们直接在 \(f\) 里找即可,可以开
map解决,注意判掉在 \([l,r]\) 内的情况。(当然map里面存储的是下标,自然能判掉了) - \(X\) 在 \([l,r]\) 内。那我们相当于找一个 \([l,r]\) 之内的 \(i\) 满足 \(X=g_{r-i+l}-g_{r+1}+f_{l-1}\)。考虑移项,变成 \(X+g_{r+1}-f_{l-1}=g_{r-i+l}\)。当然所有 \(r-i+l\in [l,r]\),所以相当于 \(X+g_{r+1}-f_{l-1}=g_{i}\)。找 \(g_{i}\) 可以开
map解决,注意判掉在 \([l,r]\) 外的情况。
当然如果我们要找的是一个数对 \(({\color{red}X},{\color{blue}Y})\) 也可以用同样的方法解决,把 map 开成 map<pair<int,int>,int> 就好了。
提示
依照现在的思路是过不了的,因为可能有两个点相同,也就是 map 可能会被重复赋值。
那么我们就可以开 vector 记录与 map 存储的点相同的点,在里面二分即可。对于 \((X,Y)\) 不在 \([l,r]\) 内的情况,我们也可以记录下标最大的点和最小的点。
代码
在这里喵:
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int N=5e5+5;
map<PII,int> mp;
map<PII,int> mp2;
map<PII,int> mp3;
int a[N],f[N],g[N];
int b[N],p[N],q[N];
vector<int> v[N];
string s;
int n,Q;
void man(){
int x,y,l,r;
cin>>x>>y>>l>>r;
if(x==0&&y==0){
cout<<"YES\n";
return;
}
int k=mp2[{x,y}];
if(k>r){
cout<<"YES\n";
return;
}
k=mp3[{x,y}];
if(k&&k<l){
cout<<"YES\n";
return;
}
x-=f[l-1];
y-=p[l-1];
x+=g[r+1];
y+=q[r+1];
k=mp[{x,y}];
auto it=lower_bound(v[k].begin(),v[k].end(),l);
if(it==v[k].end()||*it>r) cout<<"NO\n";
else cout<<"YES\n";
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cin>>n>>Q;
cin>>s;
for(int i=1;i<=n;i++){
if(s[i-1]=='R') a[i]=1;
else if(s[i-1]=='L') a[i]=-1;
else if(s[i-1]=='U') b[i]=1;
else if(s[i-1]=='D') b[i]=-1;
f[i]=f[i-1]+a[i];
p[i]=p[i-1]+b[i];
mp2[{f[i],p[i]}]=i;
}
for(int i=n;i>=1;i--){
g[i]=g[i+1]+a[i];
q[i]=q[i+1]+b[i];
mp3[{f[i],p[i]}]=i;
}
for(int i=1;i<=n;i++){
auto tmp=make_pair(g[i],q[i]);
if(mp[tmp]==0) mp[tmp]=i;
v[mp[tmp]].push_back(i);
}
while(Q--) man();
return 0;
}
后记
都看到这里了喵,点个赞好不好喵~

浙公网安备 33010602011771号