CF - 494B - 字符串预处理 + DP

来源:互联网 发布:linux 6.0语言改为中文 编辑:程序博客网 时间:2024/05/29 06:46

problem:

http://codeforces.com/problemset/problem/494/B

给你两个字符串。s 和 t , 长度不超过1e5

问有多少1, a2, ..., ak 和 b1, b2, ..., bk 序列对满足以下:

  • k ≥ 1
  •   t is a substring of string saisai + 1... sbi (string s is considered as 1-indexed).
input
ababaaba
output
5
input
welcometoroundtwohundredandeightytwod
output
274201
input
dddd
output
12

think:

1. 首先要解读题意。有点抽象。这个看一下样例就好了。

第一个样例:

1,3

1,4

1,5

2,5

3,5
第三个样例:
1,1
1,2
1,3
2,2
2,3
3,3
12,12
12,13
13,13
13,23
23,23
123,123
比如13,23表示 a = 1,3  b = 2,3 

2. 预处理pre数组,表示第i个字符,前面,最靠后的可以和他sub的位置。

3. 前 j 位是一起的。。。然后从 j+1 到 i 组成一个新的(因为他要求 ai > b(i-1))

前j位是dp[j]
从j+1到i是 pri[i] - j 。 因为新加进来的左区间是是 j+1 ~ pri[i]  右区间是 i
然后把这两块乘起来,dp[j] * (pre[i]-j)
然后枚举所有可能的 j  然后展开一下,就O(n)了,
然后加上pri[i], 表示数组只有 1 个,没有 j 
   综上
dp[i] = sum(dp[j] * (pre[i] - j), j < pre[i]) + pre[i] = sum(dp[j]) * pre[i] - sum(dp[j] * j) + pre[i] = sum1[pre[i]-1] * pre[i] - sum2[pre[i] - 1] + pre[i]
sum1[i] = sum[i-1] + dp[i]
sum2[j] = sum[i-1] + dp[i] * i

code:

const int mod = 1000000007;const int N = 100100;char a[N];char b[N];int pre[N];int dp[N];int sum1[N];int sum2[N];int fail[N];int match[N];int nb, na;void get_fail(int *fail, const char *p){    fail[0] = -1;    for(int i = 1; p[i]; ++i){        int j = fail[i-1];        while(j != -1 && p[j+1] != p[i]) j = fail[j];        fail[i] = (p[i] == p[j+1] ? j + 1 : -1);    }}void kmp(const char *a, const char *b, const int na, const int nb){    match[0] = (a[0] == b[0] ? 0 : -1);    if(match[0] == nb - 1) pre[1] = 1;    else pre[1] = 0;    for(int i = 1; a[i]; ++i){        int j = match[i-1];        if(j == nb - 1) j = fail[j];        while(j != -1 && a[i] != b[j+1]) j = fail[j];        match[i] = (a[i] == b[j+1] ? j + 1 : -1);        if(match[i] == nb - 1) pre[i + 1] = i + 2 - nb;        else pre[i + 1] = pre[i];    }}int main(){    scanf("%s%s", a, b);    int na = strlen(a);    int nb = strlen(b);    get_fail(fail, b);    kmp(a, b, na, nb);    int ans = 0;    for(int i = 1; i <= na; ++i) if(pre[i] > 0){        dp[i] = (LL)sum1[pre[i]-1] * pre[i] % mod;        dp[i] = (dp[i] - sum2[pre[i]-1] + mod) % mod;        dp[i] = (dp[i] + pre[i]) % mod;        ans = (ans + dp[i]) % mod;        sum1[i] = (sum1[i-1] + dp[i]) % mod;        sum2[i] = (sum2[i-1] + (LL)dp[i] * i % mod) % mod;    }    printf("%d\n", ans);    return 0;}


0 0