每次取最长的最左边一段,可以使用优先队列来实现。而对于每次删除一段则可以使用链表来实现,事实上这里使用数组来模拟链表会有更好的效果。而且最后的评测使用g++会TLE(应该是我代码残了),使用c++可以过。
#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
struct Node
{
char c;
int pos, len;
Node(char c, int a, int b)
{
this->c = c; pos = a; len = b;
}
};
bool operator<(const Node& a, const Node& b)
{
if (a.len == b.len) return a.pos > b.pos;
else return a.len < b.len;
}
const int MAXN = 1000005;
char s[MAXN];
int pre[MAXN], next[MAXN];
bool vis[MAXN];
priority_queue<Node> q;
int main()
{
scanf("%s", s);
int pos = 0, n = strlen(s);
while (s[pos] != '\0')
{
int st = pos, len = 1;
while (s[++pos] == s[st]) len++;
q.push(Node(s[st], st, len));
}
for (int i = 0; s[i] != '\0'; i++)
{
pre[i] = i - 1;
next[i] = i + 1;
}
memset(vis, false, sizeof(vis));
while (!q.empty())
{
Node pnt = q.top(); q.pop();
if (pnt.len <= 1) break;
if (vis[pnt.pos]) continue;
printf("%c", pnt.c);
int front = pre[pnt.pos], back = pnt.pos;
for (int i = 0; i < pnt.len; i++, back = next[back])
{
vis[back] = true;
printf(" %d", back + 1);
}
printf("\n");
if (front >= 0) next[front] = back;
if (back < n) pre[back] = front;
if (front < 0 || back >= n || s[front] != s[back]) continue;
int len = 2;
while (pre[front] >= 0 && s[pre[front]] == s[front])
{
front = pre[front];
len++;
}
while (next[back] < n && s[back] == s[next[back]])
{
back = next[back];
len++;
}
q.push(Node(s[front], front, len));
}
return 0;
}