P2679 子串

知识点:DP

原题面

\(f[i][j][k]\) 表示 , \(a\) 字串到第 \(i\) 个字符, \(b\) 字串到第 \(j\) 个字符,
使用了 \(k\) 个子串,并且 \(a\) 中第 \(i\) 个字符必须选的方案数

\(ans[i][j][k]\) 表示, \(a\) 字串到第 \(i\) 个字符, \(b\) 字串到第 \(j\) 个字符,
使用了 \(k\) 个子串 , 总方案数,
\(ans\) 数组实际上为 \(f\) 数组的前缀和

三层循环枚举 \(a\) 字串的字符 , \(b\) 字串的字符 , 使用的字串数量
则有状态转移方程式为:

1. f[i][j][k] = 0;    							//(a[i]!=b[j]);
2. f[i][j][k] = f[i][j-1][k] + ans[i][j-1][k-1] //(a[i]==a[j]);

更新 \(f\) 后,再更新 \(ans\) 即可.

由于此题只有 \(128mb\) 的空间限制
直接开 \(f[1000][200][200]\) 会爆炸
观察转移方程式 ,
可以使用滚动数组滚掉 \(i\)


#include<cstdio>
#include<string>
#include<iostream>
#include<ctype.h>
#define int long long
//============================================================
const int mod = 1e9+7;
int lth1,lth2,num;
int f[2][210][210];// 滚动到第i个 , B到达第j位 , 使用了k个子串 
int ans[2][210][210]={1};//总方案数 
std::string a,b;
int now = 1;
//============================================================
inline int read()
{
	int fl=1,w=0;char ch=getchar();
	while(!isdigit(ch) && ch!='-') ch=getchar();
	if(ch=='-') fl=-1;
	while(isdigit(ch)){w=w*10+ch-'0',ch=getchar();}
	return fl*w;
}
//============================================================
signed main()
{
	lth1=read(),lth2=read(),num=read();
	std::cin>>a>>b;
	for(int i=1;i<=lth1;i++)//枚举a字串中的字符 
	{
	  ans[now][0][0]=1;
	  for(int j=1;j<=lth2;j++)//枚举b字串中的字符 
	    for(int k=1;k<=num;k++)
	    {
	      if(a[i-1] == b[j-1]) f[now][j][k]=(f[!now][j-1][k] + ans[!now][j-1][k-1])%mod;//可以匹配 
 	      else f[now][j][k]=0;//不可匹配 
 	      ans[now][j][k]=(ans[!now][j][k] + f[now][j][k])%mod;//更新前缀和 
		}
	  now=!now;
	}
    std::cout<<ans[!now][lth2][num];
}


//10分暴力字符串匹配 
#include<cstdio>
#include<iostream>
#include<string> 
#include<ctype.h>
//=============================================================
int n,m,k,ans;
std::string a,b;
//=============================================================
inline int read()
{
    int s=1, w=0; char ch=getchar();
    for(; !isdigit(ch);ch=getchar()) if(ch=='-') s =-1;
    for(; isdigit(ch);ch=getchar()) w = w*10+ch-'0';
    return s*w;
}
//=============================================================
signed main()
{
	n=read(),m=read(),k=read();
	std::cin>>a;std::cin>>b;
	for(int pos=a.find(b,0);pos!=-1;pos=a.find(b,pos+1)) 
	  ans++;//循环匹配b串 
	printf("%d",ans);
} 
posted @ 2019-09-07 11:19  Luckyblock  阅读(120)  评论(0)    收藏  举报