「AHOI 2013」差异 「SA」「单调栈」

首先明确题目要我们求什么。看到后面的 \(LCP(T_i, T_j)\) 很容易用后缀数组将其转化成 \(\min_{rk[i] < k \leq rk[j]}{height[k]}\)。\((若rk[i] < rk[j])\)

考虑计算每个位置的h作为min出现的次数。很明显这个东西可以用单调栈一步求出来。那么就转为计算

\(\sum_{p = l} ^ {i} \sum_{p = i} ^ {r} (n - sa[i - 1] + 1) + (n - sa[i] + 1)\)。

然后大家只要有脑子就可以发现上面那个式子加起来是\(\sum_{i = 1} ^ {n} i * (n - 1)\),因为任何一个长度为\(i\)的后缀都会被计算\(n-1\)次。

那么这个题就做完了,注意单调栈的l,r求法并不相同,因为要考虑去掉重复。

#include <bits/stdc++.h>

#pragma GCC optimize(2)

#define rep(i, l, r) for (int i = (l); i <= (r); ++i)
#define per(i, r, l) for (int i = (r); i >= (l); --i)
using namespace std;

typedef long long ll;
typedef pair <int, int> pii;
typedef vector <int> vi;

int gi() {
    int f = 1, x = 0; char ch = getchar();
    while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
    while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
    return f * x;
}

const int N = 500010;
int sa[N], rk[N], px[N], cnt[N], rk_[N], id[N], h[N], n;
int st[N], tp, l[N], r[N];
char s[N];
ll pref[N];
bool cmp(int x, int y, int w) {
    return rk_[x] == rk_[y] && rk_[x + w] == rk_[y + w];
}
void get_SA() {
    int i, j, m = 300, p, w;
    for (i = 1; i <= n; ++i) ++cnt[rk[i] = s[i]];
    for (i = 1; i <= m; ++i) cnt[i] += cnt[i - 1];
    for (i = n; i >= 1; --i) sa[cnt[rk[i]]--] = i;
    for (w = 1; w < n; w <<= 1, m = p) {
        for (p = 0, i = n; i > n - w; --i) id[++p] = i;
        for (i = 1; i <= n; ++i) if (sa[i] > w) id[++p] = sa[i] - w;
        memset(cnt, 0, sizeof(cnt));
        for (i = 1; i <= n; ++i) ++cnt[px[i] = rk[id[i]]];
        for (i = 1; i <= m; ++i) cnt[i] += cnt[i - 1];
        for (i = n; i >= 1; --i) sa[cnt[px[i]]--] = id[i];
        memcpy(rk_, rk, sizeof(rk));
        for (p = 0, i = 1; i <= n; ++i)
            rk[sa[i]] = cmp(sa[i - 1], sa[i], w) ? p : ++p;
    }
    for (i = 1, j = 0; i <= n; ++i) {
        if (rk[i] == 1) continue;
        int pos = sa[rk[i] - 1];
        while (s[i + j] == s[pos + j]) ++j;
        h[rk[i]] = j;
        if (j) --j;
    }
//  cout << "height: ";
//  for (i = 1; i <= n; ++i) cout << h[i] << " ";
//  cout << '\n';
}
ll SUM(ll l, ll r) {
    return pref[r] - pref[l - 1];
}
int main() {
    scanf ("%s", s + 1);
    n = strlen(s + 1);
    get_SA();
    rep (i, 1, n) l[i] = 0, r[i] = n + 1;
    for (int i = 1; i <= n; ++i) {
        while (tp && h[st[tp]] >= h[i]) --tp;
        if (tp) l[i] = st[tp];
        st[++tp] = i;
    }
    tp = 0;
    for (int i = n; i >= 1; --i) {
        while (tp && h[st[tp]] > h[i]) --tp;
        if (tp) r[i] = st[tp];
        st[++tp] = i;
    }
    for (int i = 1; i <= n; ++i) pref[i] = pref[i - 1] + sa[i];
    ll ans = 0, ANS = 0;
    for (int i = 1; i <= n; ++i) ans += 1LL * i * (n - 1);
    for (int i = 1; i <= n; ++i) {
        int seg_l = l[i] + 1, seg_r = r[i] - 1;
        ll ways = (i - seg_l + 1) * 1ll * (seg_r - i + 1);
        ANS += ways;
        ans += -2LL * h[i] * ways;
    }
    cout << ans << '\n';
  return 0;
}

原文地址:https://www.cnblogs.com/LiM-817/p/12302143.html

时间: 2024-07-31 19:09:20

「AHOI 2013」差异 「SA」「单调栈」的相关文章

【AHOI 2013】差异

\((\displaystyle \sum^{}_{1<=i<j<=n}{i+j})-2*\displaystyle \sum^{}_{1<=i<j<=n}{lcp(suf(i),suf(j))}\) \(=(n-1)*Σi-2*\displaystyle \sum^{}_{1<=i<j<=n}{lcp(suf(i),suf(j))}\) \(=\frac{(n-1)*(1+n)*n}{2}-2*\displaystyle \sum^{}_{1<

【BZOJ3238】差异(后缀数组,单调栈)

题意: 思路:显然len(t[i])+len(t[j])这部分的和是一定的 那么问题就在于如何快速求出两两之间lcp之和 考虑将它们排名后用SA可以很方便的求出lcp,且对答案没有影响,因为形式都是数对 所以用SA求出height 每个位置的height作为lcp的区间为扩展到最左最右,直到height[x]<height[i],height[y]<height[i] 这样合法的左区间为[x+1,i],右区间为[i,y-1] 考虑如何维护一个支持寻找最靠近当前位置的比当前位置上的数小的位置 这

【翻译】西川善司「实验做出的游戏图形」「GUILTY GEAR Xrd -SIGN-」中实现的「纯卡通动画的实时3D图形」的秘密,前篇(1)

http://www.4gamer.net/games/216/G021678/20140703095/ 新连载「实验做出的游戏图形」,是聚焦在特定游戏的图形上, 对它的结构和使用的技术解说为主旨.之前笔者连载的「西川善司的3D游戏入迷」,覆盖范围都很广,而与特定游戏强关联的技术解说,会在今后的新连载中处理. 作为纪念的第一回选择的,是Arc System Works开发的,2014年2月在街机上运作的格斗游戏「GUILTY GEAR Xrd -SIGN-」 全3D图形的GUILTY GEAR

转: 拒绝「技术栈」选择恐惧症

所谓最小化可行产品(Minimum Viable Product,MVP),就是将产品快速推向客户,从客户反馈中不断进行迭代.更重要的是,MVP 也是研发团队进一步完善产品的基础. 但是,在正式代码之前,你需要选择今后支撑产品的 技术栈,也就是要选择好整个产品每一层所要应用的技术语言.架构等. 技术栈的选择往往是创始人面临的艰难问题.无论是技术人员还是非技术人员,如果不具体了解每个语言和架构的特点,面对现在如此多元化的IT技术,简直能逼死纠结症患者.而且,如果选错了语言或者框架,很可能会导致较为

BZOJ 3238 AHOI 2013 差异 后缀数组+单调栈

题目大意: 思路:一看各种后缀那就是后缀数组没跑了. 求出sa,height之后就可以乱搞了.对于height数组中的一个值,height[i]来说,这个值能够作为lcp值的作用域只在左边第一个比他小的位置到右边第一个比他小的位置.这个东西很明显可以倍增RMQ+二分/单调栈. 之后就是数学题了 Σlen[Ti] + len[Tj] = (len + 1) * len * (len - 1),之后吧所有求出来的Σ2 * lcp(Ti,Tj)减掉就是答案. 记得答案开long long CODE:

[BZOJ 3238] [AHOI 2013] 差异

题目链接:BZOJ - 3238 题目分析 显然,这道题就是求任意两个后缀之间的LCP的和,这与后缀数组的联系十分明显. 求出后缀数组后,求出字典序相邻两个后缀的LCP,即 Height 数组. 那么我们可以用这个 Height 数组求出所有后缀之间 LCP 的和. 我们用 f[i] 表示字典序第 i 的后缀与字典序在 i 之后的所有后缀的 LCP 的和. 我们知道,两个后缀的 LCP 为 Height 数组中这两个后缀之间的最小值. 我们从最后向前推 i ,用一个单调栈维护后面的 Height

[AHOI 2013] 差异

[题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=3238 [算法] 首先 , LCP(Ti , Tj) = min{ height[rank[Ti] + 1] , height[rank[Ti] + 2] , ... , height[rank[Tj]] }          显然 , 我们只要计算后缀两两之间的LCP之和即可 对于一个右端点R , 随着L的减小 , min{height[L] , height[L + 1] ..

[bzoj3238]差异(后缀数组+单调栈)

显然我们可以先把len(Ti)+len(Tj)的值先算出来,再把LCP减去.所有len(Ti)+len(Tj)的值为n*(n-1)*(n+1)/2,这个随便在纸上画一画就可以算出来的. 接下来问题就是如何把LCP减去.我们先用后缀数组把height求出来,当有一段区间l~r,height[i]为height[l]~height[r]中的最小值,那么在l~r当中随便取两个后缀,他们的LCP则都是height[i],这个很好理解吧.那么l~r这个区间里有(l-i+1)*(r-i+1)对后缀,所以我们

【bzoj3238】[Ahoi2013]差异 后缀数组+单调栈

题目描述 输入 一行,一个字符串S 输出 一行,一个整数,表示所求值 样例输入 cacao 样例输出 54 题解 后缀数组+单调栈,几乎同 bzoj3879 的后半部分. 我明显是做题做反了... 这里还是说一下这道题的做法. 先用后缀数组求出height. 然后由于有LCP(a,c)=min(LCP(a,b),LCP(b,c))(rank[a]<rank[b]<rank[c]),所以我们只需要知道排名相邻的两个后缀的LCP,而这就是height数组的定义. 转化为子问题:给出n个数,求所有子