zoukankan      html  css  js  c++  java
  • 字符串复习笔记

    kmp(exKMP)

    「NOIP2020」字符串匹配

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 1 << 20 | 10, S = 30;
    
    int T, n, z[N], pre[S], suf[S], pc, sc, sum1, sum2, tot, cnt[S]; 
    
    char s[N]; long long ans;
    
    int main() {
        freopen("string.in", "r", stdin);
        freopen("string.out", "w", stdout);
        scanf("%d", &T);
        while (T--) {
            for (int c = 0; c < 26; c++) pre[c] = suf[c] = cnt[c] = 0;
            pc = sc = tot = sum1 = sum2 = ans = 0;
            scanf("%s", s); n = strlen(s);
            int l = 0, r = 0; z[0] = 0;
            for (int i = 1; i < n; i++) {
                if (i > r) {
                    z[i] = 0;
                    while (z[i] < n && s[z[i]] == s[i + z[i]]) z[i]++;
                    r = i + z[i] - 1, l = i;
                }
                else {
                    z[i] = min(r - i + 1, z[i - l]);
                    while (z[i] < n && s[z[i]] == s[i + z[i]]) z[i]++;
                    if (r < i + z[i] - 1) r = i + z[i] - 1, l = i;
                }
            }
            for (int i = 0; i < n; i++) suf[s[i] - 'a'] ^= 1;
            for (int c = 0; c < 26; c++) tot += suf[c];
            sc = tot;
            for (int i = 1; i < n; i++) {
                int c = s[i - 1] - 'a', k = min(z[i], n - i - 1) / i + 1;
                sum1 += (suf[c] ? -cnt[sc--] : cnt[++sc]), suf[c] ^= 1;
                ans += (k + 1ll) / 2 * sum1;
                pc += (pre[c] ? -1 : 1), pre[c] ^= 1;
                ans += 1ll * k / 2 * sum2;
                cnt[pc]++;
                if (pc <= sc) sum1++;
                if (pc <= tot) sum2++;
            }
            cout << ans << endl;
        }
        return 0;
    }
    View Code

    「JSOI2019」节日庆典

    「HNOI2019」JOJO

     

    字典树

    [FJOI2015]火星商店问题

     

    ac自动机

    「BJOI2019」奥术神杖

    #include <bits/stdc++.h>
    
    #define eps 1e-3
    #define inf 1e18
    
    using namespace std;
    
    const int N = 1510;
    
    int n, m, sze[N], nodeid, tr[N][10], fa[N]; 
    
    double val[N]; char t[N], s[N], p[N];
    
    void ins(char *str, double v) {
        int u = 0;
        for (int i = 0; str[i]; i++) {
            int c = str[i] - '0';
            if (!tr[u][c]) tr[u][c] = ++nodeid;
            u = tr[u][c];
        }
        sze[u]++, val[u] += v;
    }
    
    int head[N], to[N], nxt[N], cnt;
    
    void add_edge(int u, int v) {
        to[++cnt] = v, nxt[cnt] = head[u], head[u] = cnt;
    }
    
    void dfs(int u) {
        sze[u] += sze[fa[u]], val[u] += val[fa[u]];
        for (int i = head[u]; i; i = nxt[i]) dfs(to[i]);
    }
    
    queue<int> q;
    
    void build() {
        for (int c = 0; c < 10; c++) if (tr[0][c]) q.push(tr[0][c]);
        while (!q.empty()) {
            int u = q.front(); q.pop();
            for (int c = 0; c < 10; c++)
                if (tr[u][c]) fa[tr[u][c]] = tr[fa[u]][c], q.push(tr[u][c]);
                else tr[u][c] = tr[fa[u]][c];
        }
        for (int i = 1; i <= nodeid; i++) add_edge(fa[i], i);
        dfs(0);
    }
    
    double f[N][N]; int las[N][N], col[N][N];
    
    double check(double mid) {
        for (int i = 1; i <= nodeid; i++) val[i] -= mid * sze[i];
        for (int i = 0; i <= n; i++) 
            for (int j = 0; j <= nodeid; j++) f[i][j] = -inf;
        f[0][0] = 0;
        for (int i = 0; i < n; i++)
            for (int u = 0; u <= nodeid; u++) {
                if (f[i][u] == -inf) continue;
                if (t[i + 1] == '.') {
                    for (int c = 0; c < 10; c++) {
                        int v = tr[u][c];
                        
                        if (f[i + 1][v] < f[i][u] + val[v]) {
                            f[i + 1][v] = f[i][u] + val[v];
                            las[i + 1][v] = u, col[i + 1][v] = c;
                        }
                    }
                }
                else {
                    int v = tr[u][t[i + 1] - '0'];
                    if (f[i + 1][v] < f[i][u] + val[v]) {
                        f[i + 1][v] = f[i][u] + val[v];
                        las[i + 1][v] = u, col[i + 1][v] = t[i + 1] - '0';
                    }
                }
            }
        for (int i = 1; i <= nodeid; i++) val[i] += mid * sze[i];
        int ans = 0;
        for (int i = 1; i <= nodeid; i++) if (f[n][i] > f[n][ans]) ans = i;
        for (int u = ans, i = n; i >= 1; u = las[i][u], i--) p[i] = col[i][u] + '0';
        return f[n][ans];
    }
    
    int main() {
        scanf("%d%d", &n, &m);
        scanf("%s", t + 1);
        for (int i = 1; i <= m; i++) {
            double v; scanf("%s%lf", s, &v);
            ins(s, log(v));
        }
        build();
        double l = 0, r = log(1e9 + 5), ans = 0;
        while (r - l > eps) {
            double mid = (l + r) / 2;
            if (check(mid) > 0) ans = mid, l = mid;
            else r = mid;
        }
        check(ans);
        for (int i = 1; i <= n; i++) putchar(p[i]);
        return 0;
    }
    View Code

    manacher

    「JSOI2016」扭动的回文串

    想了个manacher+hash+二分的方法,写到一半困死了就鸽惹

     

    回文自动机

    CF932G. Palindrome Partition

    #include <bits/stdc++.h>
    
    #define Mod 1000000007
    
    using namespace std;
    
    const int N = 1e6 + 10;
    
    int n, fa[N], tr[N][26], len[N], d[N], pre[N], las, nodeid, dp[N], g[N]; char s[N], t[N];
    
    void ins(int c, int m) {
        int u = las;
        while (t[m - len[u] - 1] != t[m]) u = fa[u];
        int now = tr[u][c];
        if (!now) {
            now = ++nodeid;
            int v = fa[u];
            while (t[m - len[v] - 1] != t[m]) v = fa[v];
            fa[now] = tr[v][c];
            tr[u][c] = now;
            len[now] = len[u] + 2;
            d[now] = len[now] - len[fa[now]];
            if (d[now] == d[fa[now]]) pre[now] = pre[fa[now]];
            else pre[now] = fa[now];
        }
        las = now;
    }
    
    inline int M(const int &o) {
        return o >= Mod ? o - Mod : o;
    }
    
    int main() {
        scanf("%s", s + 1); n = strlen(s + 1);
        if (n & 1) return puts("0"), 0;
        for (int i = 1; (i << 1) <= n; i++) t[i * 2 - 1] = s[i], t[i * 2] = s[n - i + 1];
        fa[0] = fa[1] = 1, len[0] = 0, len[1] = -1, nodeid = 1;
        dp[0] = 1;
        for (int i = 1; i <= n; i++) {
            ins(t[i] - 'a', i);
            for (int j = las; j > 1; j = pre[j]) {
                g[j] = dp[i - len[pre[j]] - d[j]];
                if (d[j] == d[fa[j]]) g[j] = M(g[j] + g[fa[j]]);
                if (!(i & 1)) dp[i] = M(dp[i] + g[j]);
            }
        }
        cout << dp[n] << endl;
        return 0;
    } 
    View Code

     

    后缀数组

    [NOI2016]优秀的拆分

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 3e4 + 10;
    
    int T, n, m, sa[N], tax[N], rak[N << 1], tmp[N << 1], num, height[N], Min[15][N], Log[N]; 
    
    char s[N];
    
    void rsort() {
        for (int i = 1; i <= m; i++) tax[i] = 0;
        for (int i = 1; i <= n; i++) tax[rak[i]]++;
        for (int i = 1; i <= m; i++) tax[i] += tax[i - 1];
        for (int i = n; i >= 1; i--) sa[tax[rak[tmp[i]]]--] = tmp[i];
        
    }
    
    void init() {
        memset(rak, 0, sizeof(rak));
        memset(tmp, 0, sizeof(tmp)); // 不能只清空到n 
        for (int i = 1; i <= n; i++) rak[i] = s[i] - 'a' + 1, tmp[i] = i, sa[i] = 0;
        m = 26, rsort();
        for (int len = 1, p = 0; p < n; m = p, len <<= 1) {
            num = 0;
            for (int i = n - len + 1; i <= n; i++) tmp[++num] = i;
            for (int i = 1; i <= n; i++) if (sa[i] > len) tmp[++num] = sa[i] - len;
            rsort(), swap(rak, tmp);
            rak[sa[1]] = p = 1;
            for (int i = 2; i <= n; i++) rak[sa[i]] = (tmp[sa[i]] == tmp[sa[i - 1]] && tmp[sa[i] + len] == tmp[sa[i - 1] + len] ? p : ++p);
            // 注意该行后面有sa[i]+len与sa[i-1]+len
        }
        int l = 0;
        for (int i = 1; i <= n; i++) {
            if (l) l--;
            int j = sa[rak[i] - 1];
            while (i + l <= n && j + l <= n && s[i + l] == s[j + l]) l++;
            height[rak[i]] = l;
        }
        Log[0] = -1;
        for (int i = 1; i <= n; i++) Min[0][i] = height[i], Log[i] = Log[i >> 1] + 1;
        for (int k = 1; (1 << k) <= n; k++)
            for (int i = 1; i + (1 << k) - 1 <= n; i++)
                Min[k][i] = min(Min[k - 1][i], Min[k - 1][i + (1 << (k - 1))]);
    }
    
    inline int MIN(const int &l, const int &r) {
        int t = Log[r - l + 1];
        return min(Min[t][l], Min[t][r - (1 << t) + 1]);
    }
    
    vector<int> lcp0[N], lcp1[N], lcs0[N], lcs1[N];
    
    int lcnt[N], rcnt[N]; long long ans;
    
    
    int main() {
        scanf("%d", &T);
        while (T--) {
            scanf("%s", s + 1); n = strlen(s + 1);
            init();
            ans = 0;
            for (int i = 1; i <= n; i++) lcnt[i] = rcnt[i] = 0;
            for (int len = 1; (len << 1) <= n; len++) {
                lcp0[len].resize(n / len + 2);
                lcp1[len].resize(n / len + 2);
                for (int i = 1; (i + 1) * len <= n; i++) {
                    int l = rak[i * len], r = rak[i * len + len];
                    if (l > r) swap(l, r);
                    lcp0[len][i] = lcp1[len][i + 1] = min(len, MIN(l + 1, r));
                } 
            }
            for (int i = 1; (i << 1) <= n; i++) swap(s[i], s[n - i + 1]);
            init();
            for (int len = 1; (len << 1) <= n; len++) {
                lcs0[len].resize(n / len + 2);
                lcs1[len].resize(n / len + 2);
                for (int i = 1; (i + 1) * len <= n; i++) {
                    int l = rak[n - i * len + 1], r = rak[n - i * len - len + 1];
                    if (l > r) swap(l, r);
                    lcs0[len][i] = lcs1[len][i + 1] = min(len, MIN(l + 1, r));
                }
            }
            for (int len = 1; (len << 1) <= n; len++) {
                for (int i = 1; (i + 1) * len <= n; i++) {
                    int l = (i + 1) * len - lcs1[len][i + 1] + len, r = (i + 1) * len + lcp1[len][i + 1] - 1;
                    if (l <= r) lcnt[l]++, lcnt[r + 1]--;
                    l = i * len - lcs0[len][i] + 1, r = i * len + lcp0[len][i] - len;
                    if (l <= r) rcnt[l]++, rcnt[r + 1]--;
                }
            }
            for (int i = 1; i <= n; i++) lcnt[i] += lcnt[i - 1], rcnt[i] += rcnt[i - 1];
            for (int i = 1; i < n; i++) ans += 1ll * lcnt[i] * rcnt[i + 1];
            cout << ans << endl;
        } 
        return 0;
    }
    View Code

     

    后缀自动机

    [NOI2018]你的名字

    SAM+线段树合并

    #include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    
    inline int read() {
        int out = 0; bool flag = false;
        register char cc = getchar();
        while (cc < '0' || cc > '9') {
            if (cc == '-') flag = true;
            cc = getchar();
        }
        while (cc >= '0' && cc <= '9') {
            out = (out << 3) + (out << 1) + (cc ^ 48);
            cc = getchar();
        }
        return flag ? -out : out;
    } 
    
    inline void write(ll x, char ch) {
        if (x < 0) putchar('-'), x = -x;
        if (x == 0) putchar('0');
        else {
            int num = 0; char cc[22];
            while (x) cc[++num] = x % 10 + 48, x /= 10;
            while (num) putchar(cc[num--]);
        }
        putchar(ch);
    }
    
    
    const int L = 5e5 + 10, N = 1e6 + 10;
    
    
    int rt[N], ls[N * 40], rs[N * 40], sum[N * 40], tot, Left, Right;
    
    void add(int &u, int l, int r, int pos) {
        if (!u) u = ++tot;
        if (l == r) sum[u]++;
        else {
            int mid = (l + r) >> 1;
            if (pos <= mid) add(ls[u], l, mid, pos);
            else add(rs[u], mid + 1, r, pos);
            sum[u] = sum[ls[u]] + sum[rs[u]];
        }
    }
    
    void merge(int &u, int x, int y) {
        if (!x || !y) u = (x | y);
        else {
            u = ++tot;
            merge(ls[u], ls[x], ls[y]), merge(rs[u], rs[x], rs[y]);
            sum[u] = sum[ls[u]] + sum[rs[u]];
        }
    }
    
    int find(int u, int l, int r) {
        if (!u || !sum[u]) return -1;
        if (l == r) return l;
        int mid = (l + r) >> 1, pos = -1;
        if (mid < Right) pos = find(rs[u], mid + 1, r);
        if (pos == -1 && Left <= mid) pos = find(ls[u], l, mid);
        return pos;
    }
    
    int n, m, tax[L], ord[N], ed[L]; char s[L], t[L]; ll ans;
    
    struct sam {
        int trans[N][26], fa[N], len[N], las, nodeid;
        
        void init() {
            for (int c = 0; c < 26; c++) trans[0][c] = 1;
            for (int u = 1; u <= nodeid; u++) 
                for (int c = 0; c < 26; c++) trans[u][c] = 0;
            las = nodeid = 1;
        }
        void ins(int c) {
            int p = las, np = ++nodeid;
            len[np] = len[p] + 1;
            for ( ; p && !trans[p][c]; p = fa[p]) trans[p][c] = np;
            if (!p) fa[np] = 1;
            else {
                int q = trans[p][c];
                if (len[q] == len[p] + 1) fa[np] = q;
                else {
                    int nq = ++nodeid; len[nq] = len[p] + 1;
                    for (int i = 0; i < 26; i++) trans[nq][i] = trans[q][i];
                    fa[nq] = fa[q], fa[q] = fa[np] = nq;
                    for ( ; p && trans[p][c] == q; p = fa[p]) trans[p][c] = nq;
                }
            }
            las = np;
        }
        void build() {
            for (int i = 1; i <= nodeid; i++) tax[len[i]]++;
            for (int i = 1; i <= n; i++) tax[i] += tax[i - 1];
            for (int i = 1; i <= nodeid; i++) ord[tax[len[i]]--] = i;
            for (int i = nodeid; i; i--) {
                int now = ord[i];
                if (now != 1) merge(rt[fa[now]], rt[fa[now]], rt[now]);
            }
        }
    } ss, st;
    
    int main() {
        freopen("name.in", "r", stdin);
        freopen("name.out", "w", stdout);
        scanf("%s", s + 1), n = strlen(s + 1);
        ss.init();
        for (int i = 1; i <= n; i++) ss.ins(s[i] - 'a'), ed[i] = ss.las;
        for (int i = 1; i <= n; i++) add(rt[ed[i]], 1, n, i);
        ss.build();
        for (int T = read(); T; T--) {
            scanf("%s", t + 1), m = strlen(t + 1);
            Left = read(), Right = read(), ans = 0;
            st.init();
            int now = 1, l = 0;
            for (int i = 1; i <= m; i++) {
                int c = t[i] - 'a'; st.ins(c);
                while (now && !ss.trans[now][c]) now = ss.fa[now], l = ss.len[now];
                now = ss.trans[now][c], l += (now != 1);
                //cout << now << " " << l << " ----------------------------- 
    ";
                int pos = -1;
                while (now > 1) {
                    pos = find(rt[now], 1, n);
                    //cout << pos << " 
    ";
                    if (pos == -1 || pos - ss.len[ss.fa[now]] < Left) now = ss.fa[now], l = ss.len[now];
                    else break;
                } 
                //cout << pos << "," << now << "," << l << " ===================
    ";
                int mat = (pos == -1 ? 0 : min(l, pos - Left + 1));
                ans += max(0, st.len[st.las] - max(mat, st.len[st.fa[st.las]]));
            }
            write(ans, '
    ');
        }
        return 0;
    }
    View Code

    后缀树与lct的结合

    区间本质不同子串个数

    #include <bits/stdc++.h> 
    
    typedef long long ll;
    
    using namespace std;
    
    const int L = 1e5 + 10, N = 2e5 + 10;
    
    int n, m, fa[N], nodeid = 1, trans[N][26], len[N], las = 1, p[L]; char s[L];
    
    void ins(int c) {
        int p = las, np = ++nodeid;
        len[np] = len[p] + 1;
        for ( ; p && !trans[p][c]; p = fa[p]) trans[p][c] = np;
        if (!p) fa[np] = 1;
        else {
            int q = trans[p][c];
            if (len[q] == len[p] + 1) fa[np] = q;
            else {
                int nq = ++nodeid; len[nq] = len[p] + 1;
                for (int k = 0; k < 26; k++) trans[nq][k] = trans[q][k];
                fa[nq] = fa[q], fa[q] = fa[np] = nq;
                for ( ; p && trans[p][c] == q; p = fa[p]) trans[p][c] = nq;
            }
        }
        las = np;
    } // sam
    
    
    #define lson u << 1, l, mid
    #define rson u << 1 | 1, mid + 1, r
    
    ll sum[L << 2], tag[L << 2], ans[N];
    
    void pushdown(int u, int len) {
        sum[u << 1] += 1ll * tag[u] * (len - (len >> 1));
        sum[u << 1 | 1] += 1ll * tag[u] * (len >> 1);
        tag[u << 1] += tag[u], tag[u << 1 | 1] += tag[u];
        tag[u] = 0;
    }
    
    void modify(int u, int l, int r, int Left, int Right, int delta) {
        //cout << u << ' ' << l << ' ' << r << " " << Left << " " << Right << endl;
        if (Left <= l && r <= Right) sum[u] += delta * (r - l + 1ll), tag[u] += delta;
        else {
            int mid = (l + r) >> 1;
            pushdown(u, r - l + 1);
            if (Left <= mid) modify(lson, Left, Right, delta);
            if (mid < Right) modify(rson, Left, Right, delta);
            sum[u] = sum[u << 1] + sum[u << 1 | 1];
        }
    }
    
    ll query(int u, int l, int r, int Left, int Right) {
        if (Left <= l && r <= Right) return sum[u];
        int mid = (l + r) >> 1; ll res = 0;
        pushdown(u, r - l + 1);
        if (Left <= mid) res += query(lson, Left, Right);
        if (mid < Right) res += query(rson, Left, Right);
        return res;
    } // segment_tree
    
    
    #define check(x) (tr[fa[x]][1] == x)
    #define isroot(x) (tr[fa[x]][0] != x && tr[fa[x]][1] != x)
    
    int tr[N][2], id[N];
    
    void pushdown(int u) {
        if (id[u]) {
            if (tr[u][0]) id[tr[u][0]] = id[u];
            if (tr[u][1]) id[tr[u][1]] = id[u];
        }
    }
    
    void pushall(int u) {
        if (fa[u]) pushall(fa[u]);
        pushdown(u);
    }
        
    void rotate(int x) {
        int y = fa[x], z = fa[y], opt1 = check(x), opt2 = check(y);
        if (!isroot(y)) tr[z][opt2] = x; fa[x] = z;
        tr[y][opt1] = tr[x][opt1 ^ 1], fa[tr[x][opt1 ^ 1]] = y;
        tr[x][opt1 ^ 1] = y, fa[y] = x;
    }
        
    void splay(int x) {
        pushall(x);
        while (!isroot(x)) {
            int y = fa[x];
            if (!isroot(y)) rotate(check(x) == check(y) ? y : x);
            rotate(x);
        }
    }
        
    void access(int x, int ed) {
        int u = x;
        for (int y = 0; x; y = x, x = fa[x]) {
            splay(x), tr[x][1] = y;
            if (id[x]) modify(1, 1, n, id[x] - len[x] + 1, id[x] - len[fa[x]], -1);
        }
        splay(u), modify(1, 1, n, 1, id[u] = ed, 1);
    } // lct
    
    
    struct que {
        int l, r, id;
        bool operator < (const que &g) const {
            return r < g.r;
        }
    } q[N];
    
    int main() {
        scanf("%s", s + 1); n = strlen(s + 1);
        for (int i = 1; i <= n; i++) ins(s[i] - 'a'), p[i] = las;
        //for (int i = 1; i <= nodeid; i++) cout << i << " " << p[i] << " " << len[i] << ' ' << fa[i] << "
    ";
        scanf("%d", &m);
        for (int i = 1; i <= m; i++) scanf("%d%d", &q[i].l, &q[i].r), q[i].id = i;
        sort(q + 1, q + m + 1);
        int now = 0;
        for (int i = 1; i <= m; i++) {
            while (now < q[i].r) ++now, access(p[now], now);
            ans[q[i].id] = query(1, 1, n, q[i].l, q[i].r);
        }
        //printf("(%d)
    ", nodeid);
        for (int i = 1; i <= m; i++) printf("%lld
    ", ans[i]);
        return 0;
    }
    View Code

     「雅礼集训 2017 Day7」事情的相似度

     

    哈希

    [JSOI2008]火星人

    splay+hash(自然溢出)

    #include <bits/stdc++.h>
    
    #define check(x) (tr[fa[x]][1] == x)
    
    using namespace std;
    
    
    inline int read() {
        int out = 0;
        bool flag = false;
        register char cc = getchar();
        while (cc < '0' || cc > '9') {
            if (cc == '-') flag = true;
            cc = getchar();
        }
        while (cc >= '0' && cc <= '9') {
            out = (out << 3) + (out << 1) + (cc ^ 48);
            cc = getchar();
        }
        return flag ? -out : out;
    } 
    
    inline void write(int x, char ch) {
        if (x < 0) putchar('-'), x = -x;
        if (x == 0) putchar('0');
        else {
            int num = 0; char cc[22];
            while (x) cc[++num] = x % 10 + 48, x /= 10;
            while (num) putchar(cc[num--]);
        }
        putchar(ch);
    }
    
    
    const int N = 100010;
    
    int n, q, rt, nodeid, tr[N][2], sze[N], fa[N]; 
    
    unsigned int arr[N], val[N], p[N];
    
    char ch;
    
    void updata(int u) {
        sze[u] = sze[tr[u][0]] + sze[tr[u][1]] + 1;
        val[u] = val[tr[u][0]] * p[sze[tr[u][1]] + 1] + arr[u] * p[sze[tr[u][1]]] + val[tr[u][1]];
    }
    
    void rotate(int x) {
        int y = fa[x], z = fa[y], opt1 = check(x), opt2 = check(y);
        fa[x] = z, tr[z][opt2] = x;
        fa[tr[x][opt1 ^ 1]] = y, tr[y][opt1] = tr[x][opt1 ^ 1];
        fa[y] = x, tr[x][opt1 ^ 1] = y;
        updata(y), updata(x);
    }
    
    void splay(int x, int goal) {
        updata(x);
        while (fa[x] != goal) {
            int y = fa[x], z = fa[y];
            if (z != goal) rotate(check(x) == check(y) ? y : x);
            rotate(x);
        }
        if (!goal) rt = x;
    }
    
    int find(int k) {
        if (k == 0) return 0;
        int u = rt;
        while (true) {
            if (k > sze[tr[u][0]] + 1) k -= sze[tr[u][0]] + 1, u = tr[u][1];
            else if (k <= sze[tr[u][0]]) u = tr[u][0];
            else return u;
        }
    }
    
    void ins(int k, int c) {
        int u = find(k), par = u, v = tr[par][1]; while (v) par = v, v = tr[par][0];
        v = ++nodeid, sze[v] = 1, arr[v] = c;
        fa[v] = par, tr[par][par == u ? 1 : 0] = v, splay(v, 0);
    }
    
    void change(int k, int c) {
        int u = find(k);
        arr[u] = c, splay(u, 0);
    }
    
    unsigned int query(int l, int r) {
        if (l == 1 && r == n) return val[rt];
        if (l == 1) return splay(find(r + 1), 0), val[tr[rt][0]];
        if (r == n) return splay(find(l - 1), 0), val[tr[rt][1]];
        int x = find(l - 1), y = find(r + 1);
        splay(x, 0), splay(y, x);
        return val[tr[y][0]];
    }
    
    int main() {
        p[0] = 1; for (int i = 1; i < N; i++) p[i] = p[i - 1] * 29u;
        ch = getchar(); while (ch < 'a' || ch > 'z') ch = getchar();
        while (ch >= 'a' && ch <= 'z') ins(n++, ch - 'a'), ch = getchar();
        for (q = read(); q; q--) {
            ch = getchar(); while (ch != 'Q' && ch != 'R' && ch != 'I') ch = getchar();
            if (ch == 'Q') {
                int x = read(), y = read();
                int l = 0, r = n - max(x, y), ans = -1;
                while (l <= r) {
                    int mid = (l + r) >> 1;
                    if (query(x, x + mid) == query(y, y + mid)) l = mid + 1, ans = mid;
                    else r = mid - 1;
                }
                write(ans + 1, '
    ');
            }
            else if (ch == 'R') {
                int x = read(); ch = getchar(); while (ch < 'a' || ch > 'z') ch = getchar();
                change(x, ch - 'a');
            }
            else {
                int x = read(); ch = getchar(); while (ch < 'a' || ch > 'z') ch = getchar();
                ins(x, ch - 'a'); n++;
            }
        }
        return 0;
    }
    View Code

    表达式树(这个不知道该归哪一个,就把它当字符串吧233)

    [WC2021]表达式求值

    改为计算每个数在所有方案中被算了几次

    最关键的在于这样一个结论

    同行不同列的两个元素(共$m$行$n$列)

    若它们各自所在列中大于等于它的元素的行号集合相同 则它们被计算次数相同

    这样就有个$Theta(2^{m-1}m|E|)$的做法

    然后我们可以不必枚举行号,最后$geq x$的减去$> x$的就可以了

    这样是$Theta(2^{m}|E|)$

    #include <bits/stdc++.h>
    
    #define Mod 1000000007
    
    using namespace std;
    
    
    inline int read() {
        int out = 0; bool flag = false;
        register char cc = getchar();
        while (cc < '0' || cc > '9') {
            if (cc == '-') flag = true;
            cc = getchar();
        }
        while (cc >= '0' && cc <= '9') {
            out = (out << 3) + (out << 1) + (cc ^ 48);
            cc = getchar();
        }
        return flag ? -out : out;
    }
    
    inline void write(int x, char ch) {
        if (x < 0) putchar('-'), x = -x;
        if (x == 0) putchar('0');
        else {
            int num = 0; char cc[22];
            while (x) cc[++num] = x % 10 + 48, x /= 10;
            while (num) putchar(cc[num--]);
        }
        putchar(ch);
    }
    
    
    int n, m, a[10][50010], len, stk[50010], tp, nodeid; 
    
    char s[50010], str[50010], tot, sgn[50010];
    
    int rt, ls[50010], rs[50010], sze[50010][2], f[1024], ans;
    
    void dfs(int u, int mask) {
        if ('0' <= sgn[u] && sgn[u] <= '9') sze[u][(mask >> (sgn[u] - '0')) & 1]++;
        else {
            dfs(ls[u], mask), dfs(rs[u], mask);
            int l0 = sze[ls[u]][0], l1 = sze[ls[u]][1];
            int r0 = sze[rs[u]][0], r1 = sze[rs[u]][1];
            if (sgn[u] != '>') {
                sze[u][0] += (1ll * (l0 + l1) * (r0 + r1) - 1ll * l1 * r1) % Mod;
                sze[u][1] += 1ll * l1 * r1 % Mod;
            }
            if (sgn[u] != '<') {
                sze[u][0] += 1ll * l0 * r0 % Mod;
                sze[u][1] += (1ll * (l0 + l1) * (r0 + r1) - 1ll * l0 * r0) % Mod;
            }
            if (sze[u][0] >= Mod) sze[u][0] -= Mod;
            if (sze[u][1] >= Mod) sze[u][1] -= Mod;
        }
    }
    
    int main() {
        n = read(), m = read();
        for (int i = 0; i < m; i++)
            for (int j = 0; j < n; j++) a[i][j] = read();
        scanf("%s", s), len = strlen(s);
        for (int i = 0; i < len; i++) {
            if ('0' <= s[i] && s[i] <= '9') stk[++tp] = ++nodeid, sgn[nodeid] = s[i];
            else {
                if (s[i] == '(') str[++tot] = '(';
                else if (s[i] == ')') {
                    while (str[tot] != '(') {
                        sgn[++nodeid] = str[tot--];
                        int x = stk[tp--], y = stk[tp--]; stk[++tp] = nodeid;
                        ls[nodeid] = x, rs[nodeid] = y;
                    }
                    tot--;
                }
                else {
                    while (tot && str[tot] != '(') {
                        sgn[++nodeid] = str[tot--];
                        int x = stk[tp--], y = stk[tp--]; stk[++tp] = nodeid;
                        ls[nodeid] = x, rs[nodeid] = y;
                    }
                    str[++tot] = s[i];
                }
            }
        }
        while (tot) {
            sgn[++nodeid] = str[tot--];
            int x = stk[tp--], y = stk[tp--]; stk[++tp] = nodeid;
            ls[nodeid] = x, rs[nodeid] = y;
        } // build expression tree
        rt = stk[1];
        for (int mask = 0; mask < (1 << m); mask++) {
            for (int i = 1; i <= nodeid; i++) sze[i][0] = sze[i][1] = 0;
            dfs(rt, mask);
            f[mask] = sze[rt][1];
        } // dp
        for (int j = 0; j < n; j++) {
            int q[11]; q[m] = 0x3f3f3f3f;
            for (int i = 0; i < m; i++) q[i] = a[i][j];
            sort(q, q + m);
            for (int i = 0; i < m; i++) if (q[i] != q[i + 1]) {
                int now = 0, nxt = 0;
                for (int k = 0; k < m; k++) 
                    now |= ((a[k][j] >= q[i]) << k), nxt |= ((a[k][j] >= q[i + 1]) << k);
                ans = (ans + 1ll * (f[now] - f[nxt]) * q[i]) % Mod;
            }
        }
        write(ans, '
    ');
        return 0;
    } 
    View Code
  • 相关阅读:
    设计模式
    LiggEasyWinApp-104-Ligg.EasyWinForm:Zone
    Ligg.EasyWinApp-10300-Ligg.EasyWinForm:View的配置
    LiggEasyWinApp-103-Ligg.EasyWinForm:View
    Ligg.EasyWinApp-102-Ligg.EasyWinForm:Function--ControlBox、Tray、Resize、Menu
    Ligg.EasyWinApp-101-Ligg.EasyWinForm: Application--启动,传入参数、读取Application级别配置文件、验证密码、软件封面、启动登录、StartForm
    Ligg.EasyWinApp-100-Ligg.EasyWinForm:一款Winform应用编程框架和UI库介绍
    Ligg.WinOa-000: Windows运维自动化编程实战--前言
    Ligg.EasyWinApp-000: 一款Windows应用编程框架介绍
    微服务分布式 spring cloud springboot 框架源码 activiti工作流 前后分离
  • 原文地址:https://www.cnblogs.com/Urushibara-Ruka/p/14538496.html
Copyright © 2011-2022 走看看