题解 P2070 【刷墙】
关于这道题,第一眼看到应该想到的是暴力吧,暴力很简单,读入后一个个打标记,最后统计一下从哪里到哪里经过的次数大于2次,再输出就好了。
但是,当我们再细细看题的时候: Bessie在她的行走中最远到达距起始点1,000,000,000个单位长度。
我的天!!!这个天才Bessie走这么远,我们要是乖乖开数组的话空间会不够的!!!这时我们又可以从什么方向入手呢?
我们回到我们一开始进行模拟的步骤,如果我们进行以下的移动的话会很简单: 3 R 2 L 3 R
| 0 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|
| 1 | 2 | 2 | 2 | 1 |
(第一行是位置,第二行是经过次数)
但如果变成这样会很麻烦: 1000000 R 500000 L 1000000 R
| 。。。这个要是要写表格的话会死人的吧;但是这简单来写的话是不是这样呢? | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 3 | 3 | 3 | 3 | 1 | 1 | 0 | 0 |
| 要是再简单点呢? | 0 | 1 | 2 | 3 |
|---|---|---|---|---|
| 1 | 3 | 3 | 1 |
这时,一个熟悉的操作浮现在我们脑海中!!!
离散化!!!
如果我们用离散化,不正好符合刚刚我们偷懒的过程吗?这里1就代表了500000,2代表了1000000,3代表了1500000!!!妈妈再也不用担心我的空间不够了!!!
这时,我们就高高兴兴地写代码去啦,但是,写着写着,发现有什么不太对,我们这样做标记,岂不是要一个一个点的去判断?我的天,这太麻烦了,我们写代码的,不是要代码越简单越好吗?(其实就懒) 我们又想了想这个步骤,欸等等,这不正是我们学习差分的时候,老师说过的区间遍历这种类型吗!!!哈哈,没错就决定是你了!差分!
所以这道题我们用了两种技巧,一个是离散化,一个是差分,都是很实用的技巧呢!
最关键的一步来了!上代码!
#include<iostream>
#include<fstream>
#include<algorithm>
using namespace std;
int n,a[2000010],b[2000010],c[2000010],now=0,ans=0,ok=0;
char A;
void deal(int last,int next){
int v1 = lower_bound(b,b+1+n,last) - b;
int v2 = lower_bound(b,b+1+n,next) - b;
c[min(v1,v2)]++;c[max(v1,v2)]--;//差分的步骤
}
int main(){
cin>>n;
a[0]=b[0]=c[0]=0;
for(int i=1;i<=n;i++){
cin>>a[i]>>A;
if(A == 'L') a[i]*= -1;
b[i]=b[i-1]+a[i];
}
sort(b,b+1+n);
int m=unique(b,b+1+n) - b;//b数组就是用来离散化的 unique是去重函数
for(int i=1;i<=n;i++){
deal(now,now+a[i]);
now+=a[i];
}
ok=c[0];
for(int i=1;i<m;i++){
if(ok > 1) ans+=b[i]-b[i-1];
ok+=c[i]; //差分后前缀和,标准步骤了吧
}
cout<<ans<<endl;
return 0;
}
本蒟蒻没写过几次代码,希望大家喜欢 orzorzorz