D
一道看上去就很链表的模拟题。
vim 使用者对此题有些莫名的感慨……
在 Normal Mode 下
- 按下 i :进入 Insert Mode 。
- 按下 f :紧接着一个小写字母 char,若当前光标后(右)方有至少一个 char ,将光标移动到其所在位置,否则不移动。
- 按下 x :删除当前光标所在位的字符,后面的字符均会前移一格。
- 按下 h :将光标向左(前)移动一格,若无法移动就不移动。
- 按下 l :将光标向右(后)移动一格,若无法移动就不移动。
- 若按下了其他字符:无任何效果。
在 Insert Mode 下
- 按下非 e 小写字母 char :在光标当前位置前插入这个字母 char。
- 按下 e :退出 Insert Mode(进入 Normal Mode)。
如果使用链表,绝大部分操作都是 的,唯一看起来具有威胁的就是按下 f 的操作,单次操作极限可以达到
,但均摊复杂度是正确的。
因为 f 操作单调右移,而题中唯一的左移操作每次只能移动一个单位,也就是说,每次 f 消耗的势能,都只能通过按下 h 来补充,对总体复杂度无影响。
#include <cstdio>
#include <list>
#include <cstring>
#include <algorithm>
#include <ctype.h>
using namespace std;
const int bufSize = 1e6;
inline char nc()
{
#ifdef DEBUG
return getchar();
#endif
static char buf[bufSize], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, bufSize, stdin), p1 == p2) ? EOF : *p1++;
}
inline void read(char *s)
{
static char c;
for (; !isalpha(c); c = nc());
for (; isalpha(c); c = nc()) *s++ = c;
*s = '\0';
}
const int maxn = 2e5 + 100;
char s[maxn],t[maxn];
list<char> now;
int len,num;
int main()
{
read(s + 1),read(t + 1);
len = strlen(s + 1),num = strlen(t + 1);
for(int i = 1;i<=len;++i) now.push_back(s[i]);
int mode = 0;//0 for normal mode,1 for insert mode
list<char>::iterator cur = now.begin();
for(int i = 1;i<=num;++i)
{
char opt = t[i];
if(mode == 0)
{
if(opt == 'i') mode = 1;
else if(opt == 'f')
{
char tar = t[++i];
list<char>::iterator it = cur;
++it;
while(it != now.end() && it != now.end())
{
if(*it == tar)
{
cur = it;
break;
}
++it;
}
}
else if(opt == 'x') cur = now.erase(cur);
else if(opt == 'h')
{
if(cur == now.begin()) continue;
--cur;
}
else if(opt == 'l')
{
if(cur == now.end()) continue;
++cur;
}
}
else
{
if(opt == 'e') mode = 0;
else now.insert(cur,opt);
}
}
for(list<char>::iterator it = now.begin();it!=now.end();++it) putchar(*it);
return 0;
} 
京公网安备 11010502036488号