题意:
给一个串s,给一个加密过程,输出密文,过程如下:
初始i = 0,重复下面直到串结束。
找一个子串,第一个字符位于[0,i),而且该子串要和以i开头的相同长度的串相等,多个合法的取最长的,如果还有多个取最左边的,设该字串长度为k。
如果不存在,输出 -1和s[i]的ascii值,i增加1。
否则输出长度k和第一个字符的位置T,i增加k。
显然i=0时一定输出-1和s[0]。
思路:
比较裸,利用SAM的联机特性,一边找一边建,还要求最小的下标就多维护一个first_endpos。
//
// main.cpp
// 1007
//
// Created by 翅膀 on 16/9/11.
// Copyright © 2016年 kg20006. All rights reserved.
//
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stdio.h>
using namespace std;
const int N = 2e5+550;
struct SAM{
int pre[N], son[N][26], maxlen[N], fend[N];
int cur, root, last;
int newnode(){
pre[++cur] = 0, maxlen[cur] = fend[cur] = 0;
memset(son[cur], 0, sizeof(son[cur]));
return cur;
}
void init(){
cur = 0;
root = last = newnode();
}
void insertc(int w, int i){
int p = last;
int np = newnode(); fend[np] = i;
maxlen[np] = maxlen[p]+1;
while(p != 0 && son[p][w] == 0) son[p][w] = np, p = pre[p];
if(p == 0) pre[np] = root;
else{
int q = son[p][w];
if(maxlen[q] == maxlen[p]+1) pre[np] = q;
else{
int nq = newnode(); fend[nq] = fend[q];
memcpy(son[nq], son[q], sizeof(son[q]));
maxlen[nq] = maxlen[p]+1;
pre[nq] = pre[q];
pre[q] = nq;
pre[np] = nq;
while(p != 0 && son[p][w] == q) son[p][w] = nq, p = pre[p];
}
}
last = np;
}
int nex(int p, int c){
return son[p][c];
}
}sam;
char s[N];
int main(int argc, const char * argv[]) {
int T, ca = 1;
scanf("%d", &T);
while(T--){
sam.init();
scanf("%s", s);
int len = (int)strlen(s);
printf("Case #%d:\n", ca++);
for(int i = 0; i < len; ){
int p = sam.root, k = 0;
while(i < len && sam.nex(p, s[i]-'a')){
p = sam.nex(p, s[i]-'a');
sam.insertc(s[i]-'a', i);
++k, ++i;
}
if(k) printf("%d %d\n", k, sam.fend[p]-k+1);
else {
sam.insertc(s[i]-'a', i);
printf("-1 %d\n", (int)s[i]);
++i;
}
}
}
return 0;
}