Luogu P5112

题面

大家好我后缀数组学魔怔了,所以我来写一发用到后缀数组的题解。

首先求出字符串 ssarkht 三个数组,用 i 代表 si 开头的后缀。

根据 lcp(i,j)=minp=rki+1rkjhtp,问题转化为区间内有多少个点对满足 minp=rki+1rkjhtpk,换句话说就是在 (rki,rkj] 这个区间里每个数都 k

由于每个数都 k,所以 <kht 就将原 ht 数组分成了若干块,rk 值在同一块里的点对有贡献,否则没贡献。设 ci 为第 i 个块中的元素个数,问题转化为对于每个询问求 ci×(ci1)2

发现这个东西可以莫队,时间复杂度 O(nlogn+nm),可过。

代码:

constexpr int N = 3e6 + 5;
int n, m, k, cnt[N], sa[N], id[N], __rk[2][N], *rk = __rk[0], *ork = __rk[1], ht[N];
char s[N];
void get_sa() {
    int m = 128, p = 0;
    rep(i, 1, n) ++cnt[rk[i] = s[i]];
    rep(i, 1, m) cnt[i] += cnt[i - 1];
    per(i, n, 1) sa[cnt[rk[i]]--] = i;
    for(int w = 1; ; m = p, p = 0, w <<= 1) {
        rep(i, n - w + 1, n) id[++p] = i;
        rep(i, 1, n) if(sa[i] > w) id[++p] = sa[i] - w;
        memset(cnt, 0, 4 * (m + 1));
        rep(i, 1, n) ++cnt[rk[i]];
        rep(i, 1, m) cnt[i] += cnt[i - 1];
        per(i, n, 1) sa[cnt[rk[id[i]]]--] = id[i];
        swap(rk, ork);
        p = 0;
        rep(i, 1, n) rk[sa[i]] = ork[sa[i]] == ork[sa[i - 1]] && ork[sa[i] + w] == ork[sa[i - 1] + w] ? p : ++p;
        if(p == n) break;
    }
}
void get_ht() {
    int k = 0;
    rep(i, 1, n) {
        if(k) --k;
        while(s[i + k] == s[sa[rk[i] - 1] + k]) ++k;
        ht[rk[i]] = k;
    }
}
int B, b[N], tot, bel[N], cc[N];
ll ans[N], res;
void get_b() {
    rep(i, 1, n) if(ht[i] < k) b[++tot] = i;
    b[tot + 1] = n + 1;
    rep(i, 1, tot) rep(j, b[i], b[i + 1] - 1) bel[sa[j]] = i;
}
struct query {
    int l, r, id;
    bool operator<(const query& b) const {
        return l / B != b.l / B ? l / B < b.l / B : (l / B & 1) ? r < b.r : r > b.r;
    }
} q[N];
inline void add(int i) { res += cc[i]++; }
inline void del(int i) { res -= --cc[i]; }
void solve() {
    int l = 1, r = 0;
    rep(i, 1, m) {
        while(l > q[i].l) add(bel[--l]);
        while(r < q[i].r) add(bel[++r]);
        while(l < q[i].l) del(bel[l++]);
        while(r > q[i].r) del(bel[r--]);
        // rep(i, 1, tot) cout << cc[i] << ' '; cout << endl;
        ans[q[i].id] = res;
    }
}
signed main() {
    cin >> n >> m >> k;
    cin >> (s + 1);
    get_sa();
    get_ht();
    get_b();
    // rep(i, 1, n) cout << sa[i] << ' '; cout << endl;
    // rep(i, 1, n) cout << rk[i] << ' '; cout << endl;
    // rep(i, 1, n) cout << ht[i] << ' '; cout << endl;
    // rep(i, 1, tot) cout << b[i] << ' '; cout << endl;
    // rep(i, 1, n) cout << bel[i] << ' '; cout << endl;
    rep(i, 1, m) cin >> q[i].l >> q[i].r, q[i].id = i;
    B = n / sqrt(m);
    sort(q + 1, q + m + 1);
    solve();
    rep(i, 1, m) cout << ans[i] << endl;
    return 0;
}
posted @   untitled0  阅读(12)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· AI与.NET技术实操系列(六):基于图像分类模型对图像进行分类
点击右上角即可分享
微信分享提示