多校训练营7

I:Suffix Sort

LyFive

标签

SA;ST表;排序

题意

对于一个字符串根据每一种字符第一次出现的顺序映射,如映射为 现给定一个字符串求其所有后缀按照此规则进行排序的序列。

思路

若不考虑规则,我们能发现排序可以直接使用求得数组。但通过规则变形后,两个相邻的后缀可能完全不相同,因此不能浅显使用进行排序。考虑字符串排序规则,对于两个字符串则一定存在一个位置使得,为此可以将问题转化为对于两个字符串如何快速的找到位置。 对于两个字符串我们通过比较每个字符的位置集合找到最小失配位置,即所求的。假设中出现的第个字符在中出现的位置分别是中出现的第个字符在中出现的位置分别是那么在第个字符的第次出现位置还不失配的充要条件就是。因此对于位置我们可以通过构造差分数组,得到相对位置关系,再使用对差分数组进行排序利用中的数组性质,构造查询即对于差分数组后缀的最长公共前缀长度。为此只需要特殊比较第一个位置,利用最长公共前缀长度便可以快速查询对于第个字符的失配位置,最终比较所有字符的失配位置取最小指即可得到所求。 对于差分数组,根据不同字符构造26个数组进行合并,并构造数组,存储每一个后缀中字符映射关系,数组存储字符串后缀起始位置对应差分数组的位置。最终用表对数组进行构造。

代码
参考代码
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
#include <bits/stdc++.h>
using namespace std;

using LL = long long;
using vi = vector<int>;
using vL = vector<LL>;
using pii = pair<int, int>;
using pLL = pair<LL, LL>;

#define x first
#define y second

const LL N = 4e5 + 100;
const LL mod = 1e9 + 7;

char s[N];
int a[N];
int ac[N];
int x[N], y[N], c[N];
int sa[N];
int h[N], rk[N];

vector<int> md[26];
int dp[N][26];
int pos[N];
int ct[N];
int n, m;

int am, bm;
int ca, cb;
int pa, pb;
int ll, rr, ms, rs;
void getSA()
{
    memset(x, 0x3f, sizeof x);
    for (int i = 1; i <= n; i++)
        c[x[i] = a[i]]++;
    for (int i = 1; i <= m; i++)
        c[i] += c[i - 1];
    for (int i = n; i >= 1; i--)
        sa[c[x[i]]--] = i;
    for (int k = 1; k <= n; k <<= 1)
    {
        int num = 0;
        for (int i = n - k + 1; i <= n; i++)
            y[++num] = i;

        for (int i = 1; i <= n; i++)
            if (sa[i] > k)
                y[++num] = sa[i] - k;

        for (int i = 0; i <= m; i++)
            c[i] = 0;
        for (int i = 1; i <= n; i++)
            c[x[i]]++;
        for (int i = 1; i <= m; i++)
            c[i] += c[i - 1];
        for (int i = n; i >= 1; i--)
            sa[c[x[y[i]]]--] = y[i], y[i] = 0;

        swap(x, y);
        num = 0;
        x[sa[1]] = ++num;
        for (int i = 2; i <= n; i++)
            x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) ? num : ++num;
        m = num;
        if (num == n)
            break;
    }

    for (int i = 1; i <= n; i++)
        rk[sa[i]] = i;
    for (int i = 1, k = 0; i <= n; i++)
    {
        if (rk[i] == 1)
            continue;
        if (k)
            k--;
        int j = sa[rk[i] - 1];

        while (i + k <= n && j + k <= n && a[i + k] == a[j + k])
            k++;
        h[rk[i]] = k;
    }
}
const int logn = 20;
int Logn[N];
int f[N][logn];

void pre()
{ // 准备工作,初始化
    Logn[1] = 0;
    Logn[2] = 1;
    for (int i = 3; i < N; i++)
    {
        Logn[i] = Logn[i / 2] + 1;
    }
    memset(f, 0x3f, sizeof f);
    for (int i = 1; i <= n; i++)
        f[i][0] = h[i];

    for (int j = 1; j <= logn; j++)
        for (int i = 1; i + (1 << j) - 1 <= n; i++)
            f[i][j] = min(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]); // ST表具体实现
}

bool cmp(int x, int y)
{
    int ps = min(n - x + 1, n - y + 1);

    for (int i = 0; i < 26; i++)
    {
        if (!dp[x][i] && !dp[y][i])
            break;
        if (dp[x][i] == 0)
        {
            ps = min(ps, dp[y][i] - y);
        }
        if (dp[y][i] == 0)
        {
            ps = min(ps, dp[x][i] - x);
        }
        if (dp[x][i] && dp[y][i])
        {
            if (dp[x][i] - x != dp[y][i] - y)
            {
                ps = min(ps, min(dp[x][i] - x, dp[y][i] - y));
            }
            else
            {
                pa = pos[dp[x][i]] + 1;
                pb = pos[dp[y][i]] + 1;
                if (a[pa] != 0 && a[pb] != 0)
                {
                    ll = min(rk[pa], rk[pb]);
                    rr = max(rk[pa], rk[pb]);
                    ll++;
                    ms = Logn[rr - ll + 1];
                    rs = min(f[ll][ms], f[rr - (1 << ms) + 1][ms]);

                    if (rs <= ct[pa])
                    {
                        ps = min(ps, ac[pa + rs] - x);
                    }
                    if (rs <= ct[pb])
                    {
                        ps = min(ps, ac[pb + rs] - y);
                    }
                }
                else if (a[pa] == 0 && a[pb] == 0)
                {
                }
                else if (a[pa] == 0)
                {
                    ps = min(ps, ac[pb] - y);
                }
                else if (a[pb] == 0)
                {
                    ps = min(ps, ac[pa] - x);
                }
            }
        }
    }

    if (x + ps > n)
        return true;
    if (y + ps > n)
        return false;
    for (int i = 0; i < 26; i++)
    {
        if (s[dp[x][i]] == s[x + ps])
            ca = i;
        if (s[dp[y][i]] == s[y + ps])
            cb = i;
    }
    if (ca == cb)
    {
        cout << x << " " << y << endl;
    }
    return ca < cb;
}

void solve()
{
    cin >> n;
    m = n + 1;
    cin >> s + 1;
    for (int i = 1; i <= n; i++)
    {
        int si = s[i] - 'a';
        md[si].push_back(i);
    }

    int cnt = 1;
    for (int i = 0; i < 26; i++)
    {
        if (md[i].size())
            a[cnt] = 0, ac[cnt] = md[i][0], pos[md[i][0]] = cnt++;
        for (int ii = 1; ii < md[i].size(); ii++)
        {
            ct[cnt - 1] = md[i].size() - ii;
            a[cnt] = md[i][ii] - md[i][ii - 1], ac[cnt] = md[i][ii], pos[md[i][ii]] = cnt++;
        }
    }

    for (int i = n; i >= 1; i--)
    {
        for (int ii = 0; ii < 26; ii++)
        {
            dp[i][ii] = dp[i + 1][ii];
        }
        int pos = 0;
        for (int ii = 0; ii < 26; ii++)
        {
            if (!dp[i][ii])
            {
                pos = ii;
                break;
            }
            else if (s[dp[i][ii]] == s[i])
            {
                pos = ii;
                break;
            }
        }
        for (int ii = pos; ii >= 1; ii--)
        {
            dp[i][ii] = dp[i][ii - 1];
        }
        dp[i][0] = i;
    }

    getSA();
    pre();
    vector<int> v(n);
    for (int i = 0; i < v.size(); i++)
        v[i] = i + 1;
    stable_sort(v.begin(), v.end(), cmp);
    for (auto x : v)
    {
        cout << x << ' ';
    }
}

int main()
{
    solve();
}

J:Melborp Elcissalc

标签
题意
思路

K:Great Party

标签
题意
思路

评论