题解:P14330 [JOI2021 预选赛 R2] 往返滑道 / Round Sugoroku
有点强度的一道题,建议升黄(花了半个小时才AC)
直接暴力模拟肯定是会TLE的。我们使用链表解决。
我们记转向点为 # 和 x。
对于每一个转向点,我们使用一个链表节点对其进行标记,并记录它的前一个和后一个转向点。
然后进行模拟。从位置 #,我们就记录已经走过的 # 的数量,即 cnt++;,然后删除这个节点,即删除这个 #。当 # 了,此时的
特别地,long long。
代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
enum Way // 定义一个只有left和right两个值的类型,用于表示方向
{
W_left = 0,
W_right
};
const int N = 2e5 + 10;
char s[N];
int n, a, cnt;
struct Node // 链表,储存前驱和后继
{
int pre, nxt;
}lst[N];
int main()
{
scanf("%d %d %s", &n, &a, s + 1);
s[0] = s[n + 1] = 'x';
int pre = 0, nxt = n + 1;
// 建链表
for(int i = 1; i <= n + 1; i ++)
{
lst[i].pre = pre;
if(s[i] == '#') pre = i, cnt ++;
}
for(int i = n; i >= 0; i --)
{
lst[i].nxt = nxt;
if(s[i] == '#') nxt = i;
}
//循环模拟
Way way = W_right;
LL ans = 0;
while(cnt)
{
if(way == W_right)
{
ans += lst[a].nxt - a;
way = W_left;
a = lst[a].nxt;
if(a != n + 1)
cnt --,
lst[lst[a].nxt].pre = lst[a].pre,
lst[lst[a].pre].nxt = lst[a].nxt;
}
else
{
ans += a - lst[a].pre;
way = W_right;
a = lst[a].pre;
if(a != 0)
cnt --,
lst[lst[a].pre].nxt = lst[a].nxt,
lst[lst[a].nxt].pre = lst[a].pre;
}
}
cout << ans << endl;
return 0;
}