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 }

 

posted @ 2017-09-15 11:43  Flowersea  阅读(339)  评论(1编辑  收藏  举报