当前位置: 首页 > article >正文

CF1098F Ж-function

【题意】
给你一个字符串 s s s,每次询问给你 l , r l, r l,r,让你输出 s s = s l , r ss=s_{l,r} ss=sl,r ∑ i = 1 r − l + 1 L C P ( s s i , s s 1 ) \sum_{i=1}^{r-l+1}LCP(ss_i,ss_1) i=1rl+1LCP(ssi,ss1)

【思路】
和前一道题一样,用了根号做法。

可以把贡献拆成两部分,第一部分是求原串中的LCP之和,显然这样有一些超过 r r r,而这些都是border,然后就用[BJWC2018] Border 的四种求法的方法来修正这一部分的贡献即可。

第一部分先用SA,然后正着扫反着扫用分块维护。

第二部分就在前一题的基础上多进行一些对长度的分类讨论就行。

#include <bits/stdc++.h>
#define ll long long
using namespace std;

const int N = 2e5 + 10, B = 250;
const int mod = 1e9 + 7;

int n, m; char s[N];
int sa[N], rk[N], height[N], st[N][20], lg[N];
vector<pair<int, int>> ask[N];
ll ans[N];
int val[N], hsh[N];
int period[N], nxt[N], jump[N], to[N], f[N];

void SA() {
    vector<int> x(N), y(N), c(N);
    int m = 256;
    for (int i = 1; i <= n; i++) c[x[i] = s[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 = 1; i <= m; i++) c[i] = 0;
        for (int i = 1; i <= n; i++) c[x[i]]++;
        for (int i = 2; 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); x[sa[1]] = num = 1;
        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;
        if (num == n) break;
        m = num;
    }
    for (int i = 1; i <= n; i++) rk[sa[i]] = i;
    int k = 0;
    for (int i = 1; i <= n; i++) {
        if (rk[i] == 1) continue;
        if (k) k--;
        int j = sa[rk[i] - 1];
        while (i + k <= n && j + k <= n && s[i + k] == s[j + k]) k++;
        height[rk[i]] = k;
    }
    lg[0] = -1;
    for (int i = 1; i <= n; i++) {
        st[i][0] = height[i];
        lg[i] = lg[i >> 1] + 1;
    }
    for (int j = 1; j <= 18; j++) {
        for (int i = 1; i + (1 << j) - 1 <= n; i++) {
            st[i][j] = min(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
        }
    }
}
int getlcp(int i, int j) {
    i = rk[i], j = rk[j];
    if (i > j) swap(i, j);
    i++;
    int t = lg[j - i + 1];
    return min(st[i][t], st[j - (1 << t) + 1][t]);
}

namespace block {
    int cnt, L[N / B + 10], R[N / B + 10], belong[N];
    int siz[N / B + 10], num[N / B + 10][B + 10], val[N / B + 10][B + 10];
    ll sum[N / B + 10];
    bool vis[N];
    void init() {
        cnt = 0;
        memset(siz, 0, sizeof(siz));
        memset(num, 0, sizeof(num));
        memset(val, 0, sizeof(val));
        memset(sum, 0, sizeof(sum));
        memset(vis, 0, sizeof(vis));
        for (int l = 1, r; l <= n; l = r + 1) {
            r = min(n, l + B - 1);
            cnt++;
            L[cnt] = l, R[cnt] = r;
            for (int i = l; i <= r; i++) {
                belong[i] = cnt;
            }
        }
    }
    void limit(int x) {
        for (int i = 1; i <= cnt; i++) {
            int tot = 0;
            while (siz[i] && val[i][siz[i]] >= x) {
                tot += num[i][siz[i]];
                sum[i] -= 1ll * num[i][siz[i]] * val[i][siz[i]];
                siz[i]--;
            }
            if (tot) {
                siz[i]++;
                num[i][siz[i]] = tot;
                val[i][siz[i]] = x;
                sum[i] += 1ll * tot * x;
            }
        }
    }
    ll calc(int l, int r) { // l < r
        l++;
        ll ret = 0;
        if (belong[l] == belong[r]) {
            for (int i = l; i <= r; i++) if (vis[i]) {
                ret += getlcp(l - 1, i);
            }
        }
        else {
            int t;
            t = belong[r];
            for (int i = L[t]; i <= r; i++) if (vis[i]) {
                ret += getlcp(l - 1, i);
            }
            r = L[t] - 1;
            t = belong[l];
            for (int i = l; i <= R[t]; i++) if (vis[i]) {
                ret += getlcp(l - 1, i);
            }
            l = R[t] + 1;
            while (l <= r) {
                ret += sum[belong[l]];
                l += B;
            }
        }
        return ret;
    }
    void ins(int pos) {
        vis[pos] = 1;
        int len = n - pos + 1;
        int t = belong[pos];
        sum[t] += len;
        for (int i = 1; i <= siz[t]; i++) {
            if (val[t][i] == len) {
                num[t][i]++;
                return;
            }
        }
        siz[t]++;
        num[t][siz[t]] = 1;
        val[t][siz[t]] = len;
        for (int i = siz[t]; i > 1; i--) {
            if (val[t][i] < val[t][i - 1]) {
                swap(val[t][i], val[t][i - 1]);
                swap(num[t][i], num[t][i - 1]);
            }
            else {
                break;
            }
        }
    }
}

int gethsh(int l, int r) {
    return (hsh[r] - 1ll * hsh[l - 1] * val[r - l + 1] % mod + mod) % mod;
}

ll getsum(int a1, int d, int n) {
    return 1ll * a1 * n - 1ll * d * n * (n - 1) / 2;
}


int main() {
    // freopen("in.in", "r", stdin);
    // freopen("out.out", "w", stdout);
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    clock_t start = clock();
    cin >> (s + 1) >> m;
    n = strlen(s + 1);
    SA();
    // for (int i = 1; i <= n; i++) {
    //     cout << sa[i] << " \n"[i == n];
    // }
    // for (int i = 1; i <= n; i++) {
    //     cout << height[i] << " \n"[i == n];
    // }
    for (int i = 1; i <= m; i++) {
        int l, r; cin >> l >> r;
        ans[i] = r - l + 1;
        if (l < r) ask[l].push_back({r, i});
    }
    block::init();
    for (int ki = 1; ki <= n; ki++) {
        block::limit(height[ki]);   
        int l = sa[ki]; 
        for (auto [r, id] : ask[l]) {
            ans[id] += block::calc(l, r);
        }
        block::ins(l);
    }
    block::init();
    height[n + 1] = 0;
    for (int ki = n; ki >= 1; ki--) {
        block::limit(height[ki + 1]);   
        int l = sa[ki]; 
        for (auto [r, id] : ask[l]) {
            ans[id] += block::calc(l, r);
        }
        block::ins(l);
    }
    val[0] = 1;
    for (int i = 1; i <= n; i++) {
        val[i] = 1ll * val[i - 1] * 257 % mod;
        hsh[i] = (1ll * hsh[i - 1] * 257 + s[i] - 'a') % mod;
    }
    map<int, int> last;
    for (int i = 1; i <= n; i++) nxt[i] = n + 1;
    for (int ki = 1; ki <= n - B + 1; ki++) {
        f[ki] = ki - 1;
        for (int i = ki + 1, j = ki - 1; i <= ki + B - 1; i++) {
            while (j > ki - 1 && s[j + 1] != s[i]) j = f[j];
            if (s[j + 1] == s[i]) j++;
            f[i] = j;
        }
        period[ki] = ki + B - 1 - f[ki + B - 1];
        int now = gethsh(ki, ki + B - 1);
        if (last[now]) nxt[last[now]] = ki;
        last[now] = ki;
    }
    last.clear();
    for (int i = 1; i <= n; i++) jump[i] = i;
    for (int i = n - B + 2; i <= n + 1; i++) to[i] = n;
    for (int i = n - B + 1; i >= 1; i--) {
        int j = i + period[i];
        if (j <= n && nxt[i] == j) to[i] = to[j], jump[i] = jump[j];
        else {
            for (int j = i + B - 1, k = i + (B - 1) % period[i]; j <= n; j++) {
                if (s[j] != s[k]) break;
                to[i] = j;
                k++; if (k == i + period[i]) k = i;
            }
        }
    }
    // clock_t end = clock();
    // cout << (double)(end - start) / CLOCKS_PER_SEC << endl;
    for (int l = 1; l < n; l++) {
        for (auto [r, id] : ask[l]) {
            ll ret = 0;
            if (r - l + 1 <= 2 * B) {
                for (int i = l + 1; i <= r; i++) {
                    int t = r - i + 1;
                    if (gethsh(l, l + t - 1) == gethsh(i, r)) {
                        ret -= getlcp(l, i);
                        ret += t;
                    }
                }
            }
            else {
                for (int t = 1; t < B; t++) {
                    if (gethsh(l, l + t - 1) == gethsh(r - t + 1, r)) {
                        ret -= getlcp(l, r - t + 1);
                        ret += t;
                    }
                }
                int x = nxt[l];
                int len = period[l];
                int count = 0;
                while (to[x] < r) {
                    // assert((++count) <= 500);
                    if (to[x] - x >= to[l] - l && (to[x] - x) % len == (to[l] - l) % len) {
                        x = to[x] - (to[l] - l);
                        int t = r - x + 1;
                        if (gethsh(l, l + t - 1) == gethsh(x, r)) {
                            ret -= getlcp(l, x);
                            ret += t;
                        }
                    }
                    x = nxt[jump[x]];
                }
                if (x + B - 1 <= r) {
                    int len1 = to[l] - l + 1;
                    int len2 = to[x] - x + 1;
                    //>
                    int t;
                    if (x + len1 - 1 < r) {
                        t = (r - x - len1) / len + 1;
                        x += t * len;
                        len2 -= t * len;
                    }
                    if (x + B - 1 <= r && len2 > len1) { 
                        //x + len1 - 1 >= r
                        t = min(len2 - len1 - 1, r - B + 1 - x) / len + 1;
                        ret -= 1ll * (to[l] - l + 1) * t;
                        ret += getsum(r - x + 1, len, t);
                        len2 -= len * t;
                        x += len * t;
                    }
                    //==
                    if (x + B - 1 <= r && len1 == len2) {
                        ret -= getlcp(l, x);
                        ret += r - x + 1;
                        len2 -= len;
                        x += len;
                    }
                    //<
                    if (x + B - 1 <= r) {
                        t = (r - B + 1 - x) / len + 1;
                        ret += 1ll * (r - to[x]) * t;
                    }
                }
            }
            ans[id] += ret;
        }
    }
    // clock_t end2 = clock();
    // cout << (double)(end2 - end) / CLOCKS_PER_SEC << endl;
    // cout << (double)(end2 - start) / CLOCKS_PER_SEC << endl;
    for (int i = 1; i <= m; i++) {
        cout << ans[i] << "\n";
    }
    // clock_t end3 = clock();
    // cout << (double)(end3 - start) / CLOCKS_PER_SEC << endl;
}

http://www.kler.cn/a/526428.html

相关文章:

  • AI学习指南HuggingFace篇-Hugging Face 的环境搭建
  • zsh安装插件
  • leetcode——对称二叉树(java)
  • 深入解析 C++17 中的 std::not_fn
  • 灰色预测模型
  • 上位机知识篇---GitGitHub
  • F. Ira and Flamenco
  • 智慧园区系统助力企业智能化升级实现管理效率与安全性全方位提升
  • B站吴恩达机器学习笔记
  • C++11之列表初始化
  • 不够专业,想更体系化
  • 【视频+图文详解】HTML基础4-html标签的基本使用
  • 2025美赛复盘总结反思(论文手)
  • 第27篇:Python开发进阶:python多线程与多进程编程
  • [LeetCode]day 5 209.长度最小的子数组
  • EWM 变更库存类型
  • Leetcode 3434. Maximum Frequency After Subarray Operation
  • 剑指 Offer II 012. 左右两边子数组的和相等
  • C++初阶 -- 泛型编程(函数模板、类模板)入门
  • Brave132 编译指南 Windows 篇:安装 Visual Studio 2022(二)
  • QT串口通信,实现单个温湿度传感器数据的采集
  • 【初识C语言】作业讲解15课
  • MATLAB语言的测试开发
  • sem_wait的概念和使用案列
  • STM32项目分享:智能温室大棚(APP版)
  • C++ 3