HDU 6153 A Secret 套路,求解前缀在本串中出现的次数

http://acm.hdu.edu.cn/showproblem.php?pid=6153

首先相当于翻转两个串,然后求s2前缀在s1中出现的次数。

这是一个套路啦

首先把两个串结合起来,中间加一个‘%‘之类的分割

设dp[i]表示前缀1---i在本串中的出现次数和

那么从后开始dp,所有dp值一开始都是1,表示前缀出现了一次,就是自己本身。

转移,设当前去到第i位,则dp[next[i + 1] - 1] += dp[i]

就是ABACABA这样,已经知道了ABACABA出现了一次,然后前后缀ABA和ABA重复出现,那么dp[3]肯定能够加上dp[7]的,dp[7]包含了dp[7]个"ABA",就这个意思。

然后减去s2串自己本身的匹配即可。

#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;
const int maxn = 2e6 + 20;
int nextliu[maxn], dp[maxn];
char str[maxn], sub[maxn];
void get_next (char str[], int nextliu[], int lenstr) {
    int i = 1, j = 0;
    nextliu[1] = 0;
    while (i <= lenstr) {
        if (j == 0 || str[i] == str[j]) {
            nextliu[++i] = ++j;
        } else j = nextliu[j];
    }
    return ;

}
const int MOD = 1e9 + 7;
int dp2[maxn];
void work() {
    scanf("%s%s", str + 1, sub + 1);
    int lenstr = strlen(str + 1), lensub = strlen(sub + 1);
    reverse(str + 1, str + 1 + lenstr);
    reverse(sub + 1, sub + 1 + lensub);
    for (int i = 1; i <= lensub; ++i) dp2[i] = 1;
    get_next(sub, nextliu, lensub);
    for (int i = lensub; i >= 1; --i) {
        int t = nextliu[i + 1] - 1;
        dp2[t] += dp2[i];
        dp2[t] %= MOD;
    }
    int to = lensub + 1;
    sub[to++] = ‘$‘;
    for (int i = 1; i <= lenstr; ++i) sub[to++] = str[i];
    sub[to] = ‘\0‘;
    to--;

    for (int i = 1; i <= to; ++i) dp[i] = 1;
    get_next(sub, nextliu, to);
    for (int i = to; i >= 1; --i) {
        int t = nextliu[i + 1] - 1;
        dp[t] += dp[i];
        dp[t] %= MOD;
    }
//    printf("%d\n", dp[2] - dp2[2]);
    LL ans = 0;
    for (int i = 1; i <= lensub; ++i) {
        ans += 1LL * i * ((dp[i] + MOD - dp2[i]) % MOD);
        ans %= MOD;
    }
    printf("%I64d\n", ans);
}

int main() {
#ifdef local
    freopen("data.txt", "r", stdin);
//    freopen("data.txt", "w", stdout);
#endif
    int t;
    scanf("%d", &t);
    while (t--) work();
    return 0;
}

其实也可以用后缀数组 + dp搞,不过TLE了,应该要用DC3,不去搞了

http://codeforces.com/contest/432/problem/D

http://acm.gdufe.edu.cn/Problem/read/id/1338

时间: 2024-10-26 02:34:26

HDU 6153 A Secret 套路,求解前缀在本串中出现的次数的相关文章

HDU 6153 A Secret(扩展kmp)

A Secret Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 256000/256000 K (Java/Others)Total Submission(s): 1530    Accepted Submission(s): 570 Problem Description Today is the birthday of SF,so VS gives two strings S1,S2 to SF as a present,wh

HDU 2087 剪花布条(模式串在主串中出现的次数主串中子串不可重叠)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2087 题意:求模式串在主串中出现的次数,与模式串匹配的子串之间不可重叠. 思路:用kmp算法解决,在匹配更新结果后,重新定位模式串时,不可用j = next[j],应该直接让j定位到模式串开头. code: 1 #include <cstdio> 2 #include <cstring> 3 4 const int MAXN = 1005; 5 6 char aa[MAXN]; 7 c

HDU 6153 A Secret(扩展KMP模板题)

A Secret Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 256000/256000 K (Java/Others) Total Submission(s): 2523    Accepted Submission(s): 934 Problem Description Today is the birthday of SF,so VS gives two strings S1,S2 to SF as a present,w

2017中国大学生程序设计竞赛 - 网络选拔赛 HDU 6153 A Secret KMP,思维

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6153 题意:给了串s和t,要求每个t的后缀在在s中的出现次数,然后每个次数乘上对应长度求和. 解法:关键在于想到把s和t都翻转之后,把t求next,然后用t去匹配s,在匹配过程中把fail指针跳到的地方加1,但是还没完,最后需要反向遍历第二个串将大串对小串的贡献加上去就可以了. 这道题是很多现场AC的代码是有漏洞的,比如bazbaba,bazbaba这个答案是34,但是很多现场AC的代码会输出31.

HDU 6153 A Secret (KMP)

题意:给定两个串,求其中一个串 s 的每个后缀在另一个串 t 中出现的次数. 析:首先先把两个串进行反转,这样后缀就成了前缀.然后求出 s 的失配函数,然后在 t 上跑一遍,如果发现不匹配了或者是已经完全匹配了,要计算,前面出现了多少个串的长度匹配也就是 1 + 2 + 3 + .... + j 在 j 处失配,然后再进行失配处理.注意别忘了,匹配完还要再加上最后的. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000"

【扩展kmp】HDU 6153 A Secret

acm.hdu.edu.cn/showproblem.php?pid=6153 [题意] 给定字符串A和B,求B的所有后缀在A中出现次数与其长度的乘积之和 A和B的长度最大为1e6 [思路] 把A和B同时反转,相当于求B的所有前缀在A中出现次数与其长度的乘积之和 换个角度,相当于A中每出现一个B的前缀,答案中就要加上该前缀的长度 考虑A中每个位置对答案的贡献,A[i...lenA-1]与B的最长公共前缀是x,则B中的前缀B[0...1],B[0....2]...B[0....x]都在A中出现,那

HDU 6153 A Secret

题意:给定两个串,求其中一个串 s 的每个后缀在另一个串 t 中出现的次数. 题解:把两个串都 reverse 一下,给 t 做个 KMP 之后让 s 在 KMP 出来的结果上跑一遍就好了. kmp模板题. #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<algorithm> #include

1686 hdu Oulipo(求模式串在文本串中出现的次数)

代码: #include<cstdio> #include<cstring> using namespace std; char a[1000005],b[10005]; int next[10005]; int LCPS[10005]; int n,m; void GetLCPS() { int j=0; int k=-1; int len=strlen(b); next[0]=-1; while(j<len) { if(k==-1||b[k]==b[j]) { LCPS[

(KMP 1.2)hdu 1686 Oulipo(计算模式串在文本串中出现的次数)

题目: Oulipo Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5985    Accepted Submission(s): 2404 Problem Description The French author Georges Perec (1936–1982) once wrote a book, La disparition,