CodeForces 873F Forbidden Indices 后缀数组

忘了当时怎么做的了,先把代码贴上,保存一下后缀数组模板。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define REP(i, a, b) for(int i = a; i < b; i++)
#define PER(i, a, b) for(int i = b - 1; i >= a; i--)
typedef long long LL;

const int maxn = 200000 + 10;

int n, sum[maxn];
char s[maxn], t[maxn];

int fi[maxn], se[maxn], c[maxn], sa[maxn];

bool equal(int *a, int i, int j, int k) {
    if(a[i] != a[j]) return false;
    if(i + k < n && j + k < n) return a[i + k] == a[j + k];
    if(i + k >= n && j + k >= n) return true;
    return false;
}

void build_sa(int m = 27) {
    int *x = fi, *y = se;
    REP(i, 0, m) c[i] = 0;
    REP(i, 0, n) c[x[i] = s[i]]++;
    REP(i, 1, m) c[i] += c[i - 1];
    PER(i, 0, n) sa[--c[x[i]]] = i;
    for(int k = 1; k <= n; k <<= 1) {
        int p = 0;
        REP(i, n - k, n) y[p++] = i;
        REP(i, 0, n) if(sa[i] >= k) y[p++] = sa[i] - k;
        REP(i, 0, m) c[i] = 0;
        REP(i, 0, n) c[x[y[i]]]++;
        REP(i, 1, m) c[i] += c[i - 1];
        PER(i, 0, n) sa[--c[x[y[i]]]] = y[i];
        swap(x, y);
        p = 1; x[sa[0]] = 0;
        REP(i, 1, n)
            x[sa[i]] = equal(y, sa[i], sa[i-1], k) ? p-1 : p++;
        if(p >= n) break;
        m = p;
    }
}

int rank[maxn], height[maxn];
void get_height() {
    REP(i, 0, n) rank[sa[i]] = i;
    int k = 0;
    REP(i, 0, n) {
        if(k) k--;
        if(!rank[i]) { k = 0; continue; }
        int j = sa[rank[i] - 1];
        while(s[i+k] == s[j+k]) k++;
        height[rank[i]] = k;
    }
}

int C[maxn];
#define lowbit(x) (x&(-x))
void init() { memset(C, -1, sizeof(C)); }
void upd(int x, int v) {
    while(x <= n) {
        C[x] = max(C[x], v);
        x += lowbit(x);
    }
}
int query(int x) {
    int ans = -1;
    while(x) {
        ans = max(ans, C[x]);
        x -= lowbit(x);
    }
    return ans;
}

int pre[maxn], suf[maxn];

int main() {
    scanf("%d\n%s\n%s", &n, s, t);
    reverse(s, s + n);
    reverse(t, t + n);
    LL ans = 0;
    REP(i, 0, n) if(t[i] == ‘0‘) { ans = n - i; break; }
    REP(i, 0, n) { s[i] -= ‘a‘ - 1; }

    build_sa();
    get_height();
    REP(i, 0, n) sum[i] = t[sa[i]] == ‘1‘;
    REP(i, 1, n) sum[i] += sum[i - 1];

    REP(i, 0, n) { upd(height[i] + 1, i); pre[i] = query(height[i]); }
    init();
    PER(i, 0, n) { upd(height[i] + 1, n - i - 1); suf[i] = n - query(height[i]) - 1; }

    REP(i, 1, n) {
        if(!height[i]) continue;
        LL len = suf[i] - pre[i];
        LL ban = sum[suf[i] - 1];
        if(pre[i] > 0) ban -= sum[pre[i] - 1];
        ans = max(ans, (LL)(len - ban) * height[i]);
    }
    printf("%I64d\n", ans);

    return 0;
}
时间: 2024-10-08 18:33:03

CodeForces 873F Forbidden Indices 后缀数组的相关文章

Codeforces 873F Forbidden Indices 字符串 SAM/(SA+单调栈)

原文链接https://www.cnblogs.com/zhouzhendong/p/9256033.html 题目传送门 - CF873F 题意 给定长度为 $n$ 的字符串 $s$,以及给定这个字符串每一个位置是否 "禁止结尾" 的信息. 一个字符串 $a$ 的价值为 $|a|\times f(a)$ . 其中 $f(a)$为 $a$ 在 $s$ 中的匹配次数(如果匹配的结尾为禁止结尾点,那么不算匹配成功) 问在所有的字符串 $a$ 中,$\max(|a|\times f(a)$

【CF873F】Forbidden Indices 后缀自动机

[CF873F]Forbidden Indices 题意:给你一个串s,其中一些位置是危险的.定义一个子串的出现次数为:它的所有出现位置中,不是危险位置的个数.求s的所有子串中,长度*出现次数的最大值. |S|<=200000 题解:板子题啊,沿着pre树统计一下子树权值和,然后用mx*权值和更新答案就好了. #include <cstdio> #include <cstring> #include <iostream> #include <algorith

codeforces 432D D . Prefixes and Suffixes(后缀数组)

题目链接: codeforces 432D 题目大意: 给出一个字符串,求有多少种长度的前缀和后缀相等,并且得到的这个子串在原字符串中出现的次数. 题目分析: 首先利用后缀数组处理出sa[i]代表排名第i位的后缀的起始位置 处理出rank[i]代表第i个位置起始的后缀的rank 处理出height[i]代表排名第i位的和排名i-1位的公共前缀的长度. 那么我们要找后缀和前缀相等的就是找到rank[0],然后按照排名,向前向后遍历,任意两个后缀的公共前缀就是他们[i,j]区间内所有height的最

codeforces Round 246 D. Prefixes and Suffixes (后缀数组 || KMP)

题目大意: 求一个子串,子串既是前缀又是后缀. 然后再求出它在整个串中出现的次数. 思路分析: 可以很容易想到如何判断一个串既是前缀又是后缀. 只需要它与 sa[0] 的lcp 等于 整个串的长度减去它的 sa 值. 然后接下来的工作是判断出现了 多少次. 首先我们想到,如果这个子串是目标前后缀. 那么出现过它的子串在sa 中的下标一定比这个串大. 因为它已经是最简的了. 然后可以直接二分求出他出现了多少次. #include <iostream> #include <cstdio>

Codeforces 432D Prefixes and Suffixes (KMP、后缀数组)

题目链接: https://codeforces.com/contest/432/problem/D 题解L 做法一: KMP 显然next树上\(n\)的所有祖先都是答案,出现次数为next树子树大小. 做法二: 后缀数组 按照height分组,二分查找即可. 代码 KMP: #include<cstdio> #include<cstdlib> #include<cstring> #include<vector> #include<utility&g

Codeforces Round #422 (Div. 2) E. Liar 后缀数组+RMQ+DP

E. Liar The first semester ended. You know, after the end of the first semester the holidays begin. On holidays Noora decided to return to Vi?kopolis. As a modest souvenir for Leha, she brought a sausage of length m from Pavlopolis. Everyone knows th

codeforces 427D Match &amp; Catch(后缀数组,字符串)

题目 参考:http://blog.csdn.net/xiefubao/article/details/24934617 题意:给两个字符串,求一个最短的子串.使得这个子串在两个字符串中出现的次数都等于1.出现的定义为:可以重叠的出现. 解法:后缀数组的应用.从小枚举长度.如果一个长度len合法的话:则一定存在这个样的sa[i]排名.sa[i]与s[i+1]的公共前缀长度大于等于len,且sa[i]与[i-1]的公共前缀长度小于len,同时sa[i+1]与[i+2]的公共前缀长度小于len,同时

Codeforces VK Cup 2015 A.And Yet Another Bracket Sequence(后缀数组+平衡树+字符串)

这题做得比较复杂..应该有更好的做法 题目大意: 有一个括号序列,可以对其进行两种操作: ·        向里面加一个括号,可以在开头,在结尾,在两个括号之间加. ·        对当前括号序列进行循环移动,即把最后一个括号拿到开头来. 上述两种操作可以做任意次,要求添加最少的括号使得原序列变成一个合法括号序列.如果有多种可能,输出字典序最小的那一个."(" < ")". 题解: 首先计算左括号和右括号的数量,可以知道,不妨假设左括号的数量大于右括号 那么

Liar CodeForces - 822E (dp,后缀数组)

大意: 给定串$s,t$, 给定整数$x$, 求判断$t$是否能划分为至多$x$段, 使这些段在$s$中按顺序,不交叉的出现. 设$dp_{i,j}$表示$s$匹配到$i$位, 划分了$j$段, 匹配到$t$中的最大位置 每次取一个极长的lcp转移即可, lcp可以二分哈希或者用后缀数组+RMQ求 #include <iostream> #include <sstream> #include <algorithm> #include <cstdio> #in