1. 程式人生 > >【noip模擬】連環

【noip模擬】連環

!= ++ emc def lib 長度 似的 sof 答案

【題目描述】

惠子說:“連環可解也”。
這說明他是一個破解機關的高手,連連環都能解開,魯班鎖什麽的自然不在話下。一位
魯班的後人非常不服氣,於是找到惠子,給他出了一道題。
他首先給了惠子一個長度為 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(\n);
        }
    }
}

【noip模擬】連環