首先是题解的做法
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
#include
#define up(i,a,b) for(int i=a;i
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
char ch = getchar(); ll x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
const int N = 1e5 + 10;
char ss[2 * N];
int n;
int a[2 * N];
int rk[2 * N], sa[2 * N], t[2 * N], t2[2 * N], c[2 * N], height[2 * N];
int nxt[N * 2][3];
void da(int *s,int sz)
{
int *x = t, *y = t2;
int m = sz;
up(i, 0, m)c[i] = 0;
up(i, 0, n)c[x[i] = s[i]]++;
up(i, 1, m)c[i] += c[i - 1];
dwd(i, n - 1, 0)sa[--c[x[i]]] = i;
for (int k = 1; k <= n; k <<= 1)
{
int p = 0;
up(i, n - k, n)y[p++] = i;
up(i, 0, n)if (sa[i] >= k)y[p++] = sa[i] - k;
up(i, 0, m)c[i] = 0;
up(i, 0, n)c[x[y[i]]]++;
up(i, 1, m)c[i] += c[i - 1];
dwd(i, n - 1, 0)sa[--c[x[y[i]]]] = y[i];
swap(x, y);
x[sa[0]] = 0;
p = 1;
up(i, 1, n)
x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + k] == y[sa[i] + k] ? p - 1 : p++;
if (p >= n)break;
m = p;
//cout << ")" << endl;
}
}
void test(int *s)
{
cout << "suffix:" << endl;
up(i, 0, n)
{
//cout << "sa" << sa[i] << endl;
up(j, sa[i], n)cout << s[j] << " ";
cout << endl;
cout <<"h: "<< height[i] << endl;
}
}
int main()
{
while (~scanf("%d\n", &n))
{
scanf("%s", ss + 1);
upd(i, 0, n + 1)up(j, 0, 2)nxt[i][j] = 0;
dwd(i, n, 1)
{
up(j, 0, 2)nxt[i][j] = nxt[i + 1][j];
a[i - 1] = nxt[i][ss[i] - 'a'] ? n - nxt[i][ss[i] - 'a'] + i : 1;
nxt[i][ss[i] - 'a'] = i;
}
a[n] = 0;
n++;
da(a, n + 5);
//test(a);
upd(i, 1, n-1)
{
printf("%d ", sa[i] + 1);
}
printf("\n");
}
return 0;
}
再说说正常人能想到的做法。
首先观察,其实这个字符串本质上是01串,替换a为0,替换b为1。
可以发现,字符串形如11110000111000111000交替出现。
在发现,当算后缀的B函数的时候,后缀的值要么只会从原来的值突变为0,要么不变。
我们考虑字符串111011101。考虑两个前缀,111011101,11101,发现他的B函数分别为012021242,01202,可以发现,他的B函数的前缀相同,0120,所以这个时候,需要比较111011101和11101中,第一个字符串字符串11101和第二个字符串的后缀1的大小。我们可以大胆假设,该字符串通过B函数排序,仅仅之和当前(例如1)数字,与后面不和他一样的数字的距离有关。
1.当距离不等时
有形如111011101,1101,B函数前两位都是01,第三位开始不同,一个是1,一个是0,发现距离越近,B函数越小。
2.当距离相等时
有111011101,11101,此时后0后面的后缀有关。于是我们先通过后缀数字进行排序,然后通过求sa函数得到。
可以简单证明正确性:
当有连续个1(或者0)时,函数值为01111111…,知道出现和他不同的数字,这个时候函数值是01111…1110,我们可以发现01两个数字都已经出现过了,故后面的数字一定不是0,且,当进行后缀排序的时候,他在当前后缀中的函数值,就是B函数的值。比如原数组1110111,我们观察后缀10111,后3个1求得的函数值,和B函数值相等(因为在他之前01都已经出现过了,不会再出现因为他之前的0或者1被去掉,从而影响当前位置成为0,即改变函数值)。
所以第一步,我们求整个数组的B函数,进行后缀排序。然后我们重新计算一个值,即当前位置的下一个,和自己不一样的位置在哪里。(这里如果使用计算长度的话,会有边界问题)然后我们需要考虑,末尾的情况,因为末尾假设是000的话,没有下一个1。这个时候设置一个虚拟的节点在n+1位置,令他的rk值即排名为-1。保证后面为空的时候,比其他任何后缀要小。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
#include
#define up(i,a,b) for(int i=a;i
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
char ch = getchar(); ll x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
const int N = 1e5 + 10;
char ss[2 * N];
int n;
int a[2 * N];
int rk[2 * N], sa[2 * N], t[2 * N], t2[2 * N], c[2 * N], height[2 * N];
int id[2 * N], dis[2 * N];
void da(int *s, int sz)
{
int *x = t, *y = t2;
int m = sz;
up(i, 0, m)c[i] = 0;
up(i, 0, n)c[x[i] = s[i]]++;
up(i, 1, m)c[i] += c[i - 1];
dwd(i, n - 1, 0)sa[--c[x[i]]] = i;
for (int k = 1; k <= n; k <<= 1)
{
int p = 0;
up(i, n - k, n)y[p++] = i;
up(i, 0, n)if (sa[i] >= k)y[p++] = sa[i] - k;
up(i, 0, m)c[i] = 0;
up(i, 0, n)c[x[y[i]]]++;
up(i, 1, m)c[i] += c[i - 1];
dwd(i, n - 1, 0)sa[--c[x[y[i]]]] = y[i];
swap(x, y);
x[sa[0]] = 0;
p = 1;
up(i, 1, n)
x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + k] == y[sa[i] + k] ? p - 1 : p++;
if (p >= n)break;
m = p;
//cout << ")" << endl;
}
}
void getheight()
{
up(i, 0, n)rk[sa[i]] = i;
int j = 0;
int k = 0;
up(i, 0, n)
{
if (k)k--;
j = sa[rk[i] - 1];
while (a[i + k] == a[j + k])k++;
height[rk[i]] = k;
}
}
void test(int *s)
{
cout << "suffix:" << endl;
up(i, 0, n)
{
cout << "sa" << sa[i] << endl;
up(j, sa[i], n)cout << s[j] << " ";
cout << endl;
cout << "h: " << height[i] << endl;
}
}
bool cmp(int a, int b)
{
if (dis[a]-a == dis[b]-b)
{
return rk[dis[a]] < rk[dis[b]];
}
else return dis[a] - a < dis[b] - b;
}
int main()
{
while (~scanf("%d\n", &n))
{
scanf("%s", ss + 1);
int posa = -1, posb = -1;
upd(i, 1, n)
{
if (ss[i] == 'a')
{
if (posa == -1)a[i-1] = 1;
else a[i-1] = i - posa + 1;
posa = i;
}
else {
if (posb == -1)a[i-1] = 1;
else a[i-1] = i - posb + 1;
posb = i;
}
}
a[n] = 0;
n += 1;
da(a, n + 5);
getheight();
//test(a);
n -= 1;
upd(i, 1, n)id[i] = i;
posa = -1; posb = -1;
dwd(i, n,1)
{
if(ss[i]=='a')
{
if (posb == -1)dis[i] = n + 1;
else dis[i] = posb;
posa = i;
}
else {
if (posa == -1)dis[i] = n + 1;
else dis[i] = posa;
posb = i;
}
}
rk[n + 1] = -1;
sort(id + 1, id + 1 + n,cmp);
upd(i, 1, n)
printf("%d ", id[i]);
printf("\n");
}
return 0;
}