zoukankan      html  css  js  c++  java
  • 【noip模拟】连环

    【题目描述】

    惠子说:“连环可解也”。
    这说明他是一个破解机关的高手,连连环都能解开,鲁班锁什么的自然不在话下。一位
    鲁班的后人非常不服气,于是找到惠子,给他出了一道题。
    他首先给了惠子一个长度为 n的字符串s和一个长度为 m 的字符串 t,现在,他有 k 个
    询问,每个询问是给出两个整数 L,R,询问任选一对(i,j)满足 1≤i≤L,n≥j≥R,删去 s 的
    [i+1,j−1]这个区间的子串,剩下两块拼在一起,求t 在其中的匹配数的期望 e。
    惠子非常擅长吹逼,但是对数学却搞不太明白,于是他请你来帮他。
    为了防止实数的精度误差,你只需要输出 e×L×(n−R+1)

    【输入格式】

    第一行一个整数 C,表示数据组数
    每组数据,第一行是三个整数n,m,k
    接下来一行字符串表示 s
    接下来一行字符串表示 t
    接下里 k 行,每行两个整数 Li,Ri,表示一组询问
    C≤5
    n≤5×10^4,m≤100,k≤5×10^4
    1≤Li<Ri-1≤n
    对于30%的数据,n≤100,k≤100


    【输出格式】

    对于每组询问,输出一行一个整数表示答案

    【样例输入】

    1
    8 5 4
    iamnotsb
    iamsb
    4 7
    3 7
    3 8
    2 7

    【样例输出】

    1
    1
    0
    0

    【题目分析】

    删去一段之后的匹配分两种,一种是本来就匹配的,删除没有影响他,另一种是本来不匹配,删除之后因为两端连接产生的新匹配。

    首先考虑第一种:设t的某个匹配为(l,r),推一下公式发现若r≤L,那么这个匹配的贡献为(L−r+1)×(n−R+1)=(L+1)(n−R+1)−r(n−R+1),那么我们可以预处理一下匹配的r的前缀和匹配数的前缀和,就可以O(1)询问出来了。而若l≥R,那么贡献是(l−R+1)×L,也类似的弄两个前缀和出来就好。

    现在考虑因为删除中间一坨而产生的新匹配,我们考虑把t拆开成两个非空部分t1,t2,显然这一种的总贡献等同于t1在[1,L]内的匹配数乘以t2在[R,n]内的匹配数,这个也可以预处理一下前缀和,询问的时候枚举拆开的位置就行了。

    【code】

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<vector>
    using namespace std;
    
    const int N = 5e4 + 5;
    typedef long long ll;
    int C, n, m, k, nxt[105], revNxt[105], lens, lent;
    ll pre[N], preCnt[N], last[N], lastCnt[N];
    ll tpre[105][N], tlast[105][N];
    char s[N], t[105], revt[105], revs[N];
    
    inline int read(){
        int i = 0, f = 1; char ch = getchar();
        for(; (ch < '0' || ch > '9') && ch != '-'; ch = getchar());
        if(ch == '-') f = -1, ch = getchar();
        for(; ch >= '0' && ch <= '9'; ch = getchar())
            i = (i << 3) + (i << 1) + (ch - '0');
        return i * f;
    }
    
    inline void wr(ll x){
        if(x < 0) putchar('-'), x = -x;
        if(x > 9) wr(x / 10);
        putchar(x % 10 + '0');
    }
    
    inline void get_t_nxt(){
        for(int i = 2, j = 0; i <= lent; i++){
            while(j && t[j + 1] != t[i]) j = nxt[j];
            if(t[j + 1] == t[i]) j++;
            nxt[i] = j;
        }
    }
    
    inline void get_r_pre(){
        for(int i = 1, j = 0; i <= lens; i++){
            pre[i] = pre[i - 1];
            preCnt[i] = preCnt[i - 1];
            while(j && s[i] != t[j + 1]) j = nxt[j];
            if(s[i] == t[j + 1]) j++;
            if(j == lent){
                pre[i] += i;
                preCnt[i]++;
                j = nxt[j];
            }
        }
    }
    
    inline void get_t_rev_nxt(){
        for(int i = 2, j = 0; i <= lent; i++){
            while(j && revt[j + 1] != revt[i]) j = revNxt[j];
            if(revt[j + 1] == revt[i]) j++;
            revNxt[i] = j;
        }
    }
    
    
    inline void get_l_last(){
        for(int i = 1, j = 0; i <= lens; i++){
            last[i] = last[i - 1];
            lastCnt[i] = lastCnt[i - 1];
            while(j && revs[i] != revt[j + 1]) j = revNxt[j];
            if(revs[i] == revt[j + 1]) j++;
            if(j == lent){
                last[i] += n - i + 1;
                lastCnt[i]++;
                j = revNxt[j];
            }
        }
    }
    
    inline void get_t_pre(){
        for(int i = 1; i <= lent; i++){
            char now[105];
            int now_nxt[105] = {0};
            for(int j = 1; j <= i; j++)
                now[j] = t[j];
            for(int k = 2, l = 0; k <= i; k++){
                while(l && now[l + 1] != now[k]) l = now_nxt[l];
                if(now[l + 1] == now[k]) l++;
                now_nxt[k] = l;
            }
            for(int k = 1, l = 0; k <= lens; k++){
                tpre[i][k] = tpre[i][k - 1];
                while(l && now[l + 1] != s[k]) l = now_nxt[l];
                if(now[l + 1] == s[k]) l++;
                if(l == i){
                    tpre[i][k]++;
                    l = now_nxt[l];
                }
            }
        }
    }
    
    inline void get_t_last(){
        for(int i = 1; i <= lent; i++){
            char now[105];
            int now_nxt[105] = {0};
            for(int j = 1; j <= i; j++)
                now[j] = revt[j];
            for(int k = 2, l = 0; k <= i; k++){
                while(l && now[l + 1] != now[k]) l = now_nxt[l];
                if(now[l + 1] == now[k]) l++;
                now_nxt[k] = l;
            }
            for(int k = 1, l = 0; k <= lens; k++){
                tlast[i][k] = tlast[i][k - 1];
                while(l && now[l + 1] != revs[k]) l = now_nxt[l];
                if(now[l + 1] == revs[k]) l++;
                if(l == i){
                    tlast[i][k]++;
                    l = now_nxt[l];
                }
            }
        }
    }
    
    int main(){
        freopen("lianhuan.in","r",stdin);
        freopen("lianhuan.out","w",stdout);
        C = read();
        while(C--){
            n = read(), m = read(), k = read();
            scanf("%s", s + 1);
            scanf("%s", t + 1);
            memcpy(revt, t, sizeof t);
            memcpy(revs, s, sizeof s);
            reverse(revt + 1, revt + m + 1);
            reverse(revs + 1, revs + n + 1);
            lent = m;
            lens = n;
            memset(nxt, 0, sizeof nxt);
            memset(revNxt, 0, sizeof revNxt);
            memset(pre, 0, sizeof pre);
            memset(last, 0, sizeof last);
            memset(tpre, 0, sizeof tpre);
            memset(tlast, 0, sizeof tlast);
            memset(preCnt, 0, sizeof preCnt);
            memset(lastCnt, 0, sizeof lastCnt);
            get_t_nxt();
            get_t_rev_nxt();
            get_r_pre();
            get_l_last();
            get_t_pre();
            get_t_last();
            while(k--){
                int L = read(), R = read();
                ll ans = 0;
                ans += preCnt[L] * (L + 1) * (n - R + 1);
                ans -= (n - R + 1) * pre[L];
                ans -= lastCnt[n - R + 1] * (R - 1) * L;
                ans += last[n - R + 1] * L;
                for(int i = 1; i <= lent; i++)
                    ans += tpre[i][L] * tlast[lent - (i + 1) + 1][n - R + 1];
                wr(ans), putchar('
    ');
            }
        }
    }
  • 相关阅读:
    hdu1686 最大匹配次数 KMP
    洛谷 P5057 [CQOI2006]简单题(树状数组)
    洛谷 P5020 货币系统
    洛谷 P5019 铺设道路(差分)
    洛谷 P1119 灾后重建(Floyd)
    洛谷 P1082 同余方程(同余&&exgcd)
    洛谷 P2384 最短路
    洛谷 P3371 【模板】单源最短路径(弱化版) && dijkstra模板
    洛谷 P1387 最大正方形
    洛谷 P2866 [USACO06NOV]糟糕的一天Bad Hair Day
  • 原文地址:https://www.cnblogs.com/CzYoL/p/7412500.html
Copyright © 2011-2022 走看看