Codeforces Round #246 (Div. 2) D. Prefixes and Suffixe 后缀数组

链接:

codeforces.com/contest/432/problem/D

题意:

给你一个字符串,求每一个和前缀匹配的后缀在这个字符串中出现的次数

题解:

先算出lcp,找到sa[i]==0的位置标记为beg,和前缀匹配的后缀一定会出现beg的左边,这个想一想明白了

我们先算出beg左边每一个后缀和beg匹配的长度,beg右边的先放到一个vector中,便于之后二分查找

我们从beg向左遍历,对于每一个dp[i],如果dp[i]==n-sa[i],就可以更新结果了,从i到beg中间的都满足,同时还要加上beg右边的

代码:

 31 int n, k;
 32 int Rank[MAXN], tmp[MAXN];
 33 int sa[MAXN], lcp[MAXN];
 34
 35 bool compare_sa(int i, int j) {
 36     if (Rank[i] != Rank[j]) return Rank[i] < Rank[j];
 37     else {
 38         int ri = i + k <= n ? Rank[i + k] : -1;
 39         int rj = j + k <= n ? Rank[j + k] : -1;
 40         return ri < rj;
 41     }
 42 }
 43
 44 void construct_sa(string S, int *sa) {
 45     n = S.length();
 46     for (int i = 0; i <= n; i++) {
 47         sa[i] = i;
 48         Rank[i] = i < n ? S[i] : -1;
 49     }
 50     for (k = 1; k <= n; k *= 2) {
 51         sort(sa, sa + n + 1, compare_sa);
 52         tmp[sa[0]] = 0;
 53         for (int i = 1; i <= n; i++)
 54             tmp[sa[i]] = tmp[sa[i - 1]] + (compare_sa(sa[i - 1], sa[i]) ? 1 : 0);
 55         for (int i = 0; i <= n; i++) Rank[i] = tmp[i];
 56     }
 57 }
 58
 59 void construct_lcp(string S, int *sa, int *lcp) {
 60     int n = S.length();
 61     for (int i = 0; i <= n; i++) Rank[sa[i]] = i;
 62     int h = 0;
 63     lcp[0] = 0;
 64     for (int i = 0; i < n; i++) {
 65         int j = sa[Rank[i] - 1];
 66         if (h > 0) h--;
 67         for (; j + h < n && i + h < n; h++)
 68             if (S[j + h] != S[i + h]) break;
 69         lcp[Rank[i] - 1] = h;
 70     }
 71 }
 72
 73 int dp[MAXN];
 74
 75 int main() {
 76     ios::sync_with_stdio(false), cin.tie(0);
 77     string s;
 78     cin >> s;
 79     construct_sa(s, sa);
 80     construct_lcp(s, sa, lcp);
 81     int beg;
 82     rep(i, 0, n + 1) if (sa[i] == 0) {
 83         beg = i;
 84         break;
 85     }
 86     memset(dp, 0x3f, sizeof(dp));
 87     dp[beg] = INF;
 88     per(i, 0, beg) dp[i] = min(dp[i + 1], lcp[i]);
 89     rep(i, beg + 1, n + 1) dp[i] = min(dp[i - 1], lcp[i - 1]);
 90     VI v;
 91     rep(i, beg + 1, n + 1) if (dp[i]) v.pb(dp[i]);
 92     sort(all(v));
 93     map<int, int> mmp;
 94     per(i, 0, beg) {
 95         if (!dp[i]) break;
 96         if (dp[i] == n - sa[i]) {
 97             mmp[dp[i]] += beg - i + 1;
 98             mmp[dp[i]] += v.end() - lower_bound(all(v), dp[i]);
 99         }
100     }
101     cout << mmp.size() + 1 << endl;
102     for (auto it : mmp) cout << it.first << ‘ ‘ << it.second << endl;
103     cout << n << ‘ ‘ << 1 << endl;
104     return 0;
105 }
时间: 2024-10-25 05:21:01

Codeforces Round #246 (Div. 2) D. Prefixes and Suffixe 后缀数组的相关文章

Codeforces Round #246 (Div. 2)

A.Choosing Teams 水题 #include <cstdio> #include <cstring> using namespace std; int main() { int n, k, ans, i, x; scanf("%d%d",&n,&k); ans = 0; for(i=0; i<n; ++i) { scanf("%d",&x); if(5-x >= k) ans++; } ans

Codeforces Round #246 (Div. 2) A,B,C,D

A.水题,输出图形 B.水题 C.概率题 /* m, n 最大数为k的总数为 k^n - (k-1)^n 所以最大数为k的期望为 (k^n - (k-1)^n) / (m^n) */ #include<bits/stdc++.h> using namespace std; int main() { int n, m; int i, j; scanf("%d%d", &m, &n); double ans = m; for(i=1; i<=m-1; ++

Codeforces Round #246 (Div. 2) B. Football Kit

题目的意思是求出每个队穿主场衣服和客场衣服的次数 每个队作为主场的次数是n-1,作为客场的次数是n-1 当每个队打主场的时候肯定穿的主场衣服 当每个队打客场时,如果客场与主场的衣服不同,则穿客场衣服   如果客场与主场的衣服相同,则穿主场衣服 则只需要标记主场每种衣服有多少球队,当作为客场时查找与客场颜色相同的主场球队有多少即可 #include <iostream> #include <map> #include <vector> #include <algor

Codeforces Round #246 (Div. 2) (ABCD详细题解)

比赛链接:http://codeforces.com/contest/432 A. Choosing Teams time limit per test:1 second memory limit per test:256 megabytes The Saratov State University Olympiad Programmers Training Center (SSU OPTC) has n students. For each student you know the numbe

Codeforces Round #246 (Div. 2)(第一次做cf)

早就想做CF,但是在校党,没办法,断网又断电,一天实在忍不住了,就跑着流量做了一次CF 看到A题,看完题就有思路了,然后一把A掉,接着做第二道,看了N久,题意不懂,泪奔啊,然后就没激情再做了, 我的第一次就这样没了...................... 链接:http://codeforces.com/contest/432/problem/A =========================================================================

Codeforces Round #246 (Div. 2) A. Choosing Teams

给定n k以及n个人已参加的比赛数,让你判断最少还能参加k次比赛的队伍数,每对3人,每个人最多参加5次比赛 #include <iostream> using namespace std; int main(){ int n,k, cnt = 0; cin >> n >> k; for(int i = 0 ; i < n; ++ i){ int a; cin >> a; if(a+k <= 5) cnt ++; } cout<<cnt

Codeforces Round #301 (Div. 2) E . Infinite Inversions 树状数组求逆序数

E. Infinite Inversions time limit per test 2 seconds memory limit per test 256 megabytes input standard input  output standard output There is an infinite sequence consisting of all positive integers in the increasing order: p = {1, 2, 3, ...}. We pe

Codeforces Round #283 (Div. 2) A. Minimum Difficulty【一个数组定义困难值是两个相邻元素之间差的最大值。 给一个数组,可以去掉任意一个元素,问剩余数列的困难值的最小值是多少】

A. Minimum Difficulty time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output Mike is trying rock climbing but he is awful at it. There are n holds on the wall, i-th hold is at height ai off the g

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

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