loj2576 「TJOI2018」str
题意:
给一个模板串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 }