1. 程式人生 > >【NOIP2017提高A組衝刺11.8】好文章 ——聯賽字串演算法複習

【NOIP2017提高A組衝刺11.8】好文章 ——聯賽字串演算法複習

題目大意:

給出長度為n的串,問這個串長度為m的子串有多少個不同的。

題解:

這其實是一道SA的裸題,求出height以後,先把長度小於m的字尾刪去,然後就這樣取,如果一個字尾和前面最後的長度大於等於m的字尾之間的height的最小值小於m,則這個可取。
SA的板子背的還是不夠熟啊,又去看了一波biao。

然而這是一道聯賽題。
所以hash就好了。
當然單hash被卡了,那就雙hash,兩個質數,兩個模數,用set的pair直接搞一下,挺好打的。
題解用神馬斯特林公式算了期望正確率,還挺高的。

Code(SA):

#include<cstdio> 
#include<cstring>
#include<algorithm> #define fo(i, x, y) for(int i = x; i <= y; i ++) #define fd(i, x, y) for(int i = x; i >= y; i --) #define max(a, b) ((a) > (b) ? (a) : (b)) #define min(a, b) ((a) < (b) ? (a) : (b)) using namespace std; const int N = 2e5 + 5; int n, m, mm; char a[N]; int tp[N], tax[N], SA[N], rank[N], he[N]; void
Rsort() { fo(i, 1, m) tax[i] = 0; fo(i, 1, n) tax[rank[tp[i]]] ++; fo(i, 1, m) tax[i] += tax[i - 1]; fd(i, n, 1) SA[tax[rank[tp[i]]] --] = tp[i]; } bool cmp(int *f, int x, int y, int c) {return f[x] == f[y] && f[x + c] == f[y + c];} void Suffix() { fo(i, 1, n) rank[i] = a[i], tp[i] = i; m = 128
; Rsort(); for(int w = 1, p = 1; p < n; w <<= 1, m = p) { p = 0; fo(i, n - w + 1, n) tp[++ p] = i; fo(i, 1, n) if(SA[i] > w) tp[++ p] = SA[i] - w; Rsort(), swap(rank, tp), rank[SA[1]] = p = 1; fo(i, 2, n) rank[SA[i]] = cmp(tp, SA[i], SA[i - 1], w) ? p : ++ p; } int j = 0, k = 0; for(int i = 1; i <= n; he[rank[i ++]] = k) for(k = k ? k - 1 : k, j = SA[rank[i] - 1]; a[i + k] == a[j + k] && max(i, j) + k <= n; k ++); } int main() { freopen("article.in", "r", stdin); freopen("article.out", "w", stdout); scanf("%d %d", &n, &mm); scanf("%s", a + 1); Suffix(); fo(i, 2, n - 1) if(SA[i] + mm - 1 > n) he[i + 1] = min(he[i + 1], he[i]); int fi = 0; int ans = 0; fo(i, 1, n) if(SA[i] + mm - 1 <= n) { if(!fi) { fi = 1; ans ++; continue; } if(he[i] < mm) ans ++; } printf("%d", ans); }

Code(hash):

#include<set>
#include<cstdio> 
#include<cstring>
#include<algorithm>
#define ll long long
#define fo(i, x, y) for(ll i = x; i <= y; i ++)
#define fd(i, x, y) for(ll i = x; i >= y; i --)
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
using namespace std;

const ll N = 2e5 + 5;

ll n, m; char a[N];

const ll p1 = 15312137, p2 = 3113791, mo = 1e9 + 7, mo2 = 1e9 + 9;

ll c[N], d[N];

set<pair<int, int> > s;

int main() {
    freopen("article.in", "r", stdin);
    freopen("article.out", "w", stdout);
    scanf("%d %d", &n, &m);
    c[0] = 1; fo(i, 1, n) c[i] = c[i - 1] * p1 % mo;
    d[0] = 1; fo(i, 1, n) d[i] = d[i - 1] * p2 % mo2;
    scanf("%s", a + 1);
    ll z = 0, e = 0;
    fo(i, 1, m)
        z = (z + c[m - i] * a[i] % mo) % mo,
        e = (e + d[m - i] * a[i] % mo2) % mo2;
    s.insert(make_pair(z, e));
    fo(i, m + 1, n) {
        z = (z - c[m - 1] * a[i - m] % mo + mo) % mo;
        z = z * p1 % mo;
        z = (z + a[i]) % mo;

        e = (e - d[m - 1] * a[i - m] % mo2 + mo2) % mo2;
        e =  e * p2 % mo2;
        e = (e + a[i]) % mo2;

        s.insert(make_pair(z, e));
    }
    printf("%d", s.size());
}