loj2576 「TJOI2018」str

本文介绍了一种利用模板串和模式串进行匹配的算法,并通过Hash算法优化匹配过程,实现高效计算所有可能组合在模板串中出现的次数。适用于字符串模式匹配问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

link

 

题意:

给一个模板串s和n个模式串,每个模式串有$a_i$种可取的串。现在要将n个模式串每个任取一种它可取的串,连接起来,记为串t,那么这种连接方式对答案的贡献为t在s中出现的次数。问所有连接方式的贡献之和。

$n\leq 100,|S|\leq 10^4.$

 

题解:

设f[i][j]表示使用前i个模式串,匹配前j位的贡献。对每个模式串的每种可能转移,使用hash判断是否匹配。

复杂度$\mathcal{O}(|S|\times \sum a_i)$。

 

花絮:

今天我生日> <,生快啦。

 

code:

 1 #include<bits/stdc++.h>
 2 #define rep(i,x,y) for (int i=(x);i<=(y);i++)
 3 #define ll long long
 4 #define inf 1000000001
 5 #define y1 y1___
 6 using namespace std;
 7 char gc(){
 8     static char buf[100000],*p1=buf,*p2=buf;
 9     return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
10 }
11 #define gc getchar
12 ll read(){
13     char ch=gc();ll x=0;int op=1;
14     for (;!isdigit(ch);ch=gc()) if (ch=='-') op=-1;
15     for (;isdigit(ch);ch=gc()) x=(x<<1)+(x<<3)+ch-'0';
16     return x*op;
17 }
18 #define N 10005
19 #define M 105
20 #define mod 1000000007
21 #define seed 233
22 #define happy_birthday 20180731
23 int n,m,now,f[2][N],h[N],pw[N],ans;//f[i][j]:使用前i个字符串,匹配前j位的匹配方案数
24 char str[N],s[N];
25 void upd(int &x,int y){x+=y;x-=x>=mod?mod:0;}
26 void init(){
27     h[0]=0;pw[0]=1;
28     rep (i,1,n){
29         h[i]=((ll)h[i-1]*seed+str[i])%happy_birthday;
30         pw[i]=(ll)pw[i-1]*seed%happy_birthday;
31     }
32 }
33 int cal(int x,int y){
34     return (h[y]+happy_birthday-(ll)h[x-1]*pw[y-x+1]%happy_birthday)%happy_birthday;
35 }
36 int main(){
37     m=read();
38     scanf("%s",str+1);n=strlen(str+1);
39     init();
40     now=0;rep (i,0,n) f[0][i]=1;//可以从任意位置开始
41     while (m--){
42         now^=1;memset(f[now],0,sizeof(f[now]));
43         for (int k=read();k;k--){
44             scanf("%s",s+1);int l=strlen(s+1);
45             int hsh=0;rep (i,1,l) hsh=((ll)hsh*seed+s[i])%happy_birthday;
46             rep (i,1,n-l+1)
47                 if (cal(i,i+l-1)==hsh) upd(f[now][i+l-1],f[now^1][i-1]);
48         }
49     }
50     rep (i,1,n) upd(ans,f[now][i]);
51     printf("%d\n",ans);
52     return 0;
53 }
View Code

 

转载于:https://www.cnblogs.com/bestFy/p/9395543.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值