Noip 2015 D2T2 子串(动态规划)

本文介绍了一种解决特定字符串匹配问题的算法:从字符串A中选取k个非空、互不重叠的子串,按原顺序拼接后与另一字符串B进行匹配,计算所有可能的匹配方案数量。该算法利用了前缀和与动态规划技巧进行优化。

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

有两个仅包含小写英文字母的字符串A和B。现在要从字符串A中取出k个互不重叠的非空子串,然后把这k个子串按照其在字符串A中出现的顺序依次连接起来得到一个新的字符串,请问有多少种方案可以使得这个新串与字符串 B 相等?注意:子串取出的位置不同也认为是不同的方案。

-----------------------------------------------------------------------------分割线-------------------------------------------------------------------------------------------------

f[i,j,k] (当前匹配到第k组,匹配完成第j位且最后一位是a[i])        s[i,j,k]=∑f[x,j,k](0<x<=i)前缀和

f[i,j,k]=0(a[i]<>b[j])当前位不相同

f[i,j,k]=s[i-1,j-1,k-1](a[i]=b[j]) and (a[i-1]<>b[j-1])前一位不相同

f[i,j,k]=s[i-1,j-1,k-1]+f[i-1,k-1,k](a[i]=b[i]) and (a[i-1]=b[j-1])

此题需要(空间)循环数组(时间)前缀和的优化方可AK

const
  model=1000000007;
var
  ans:qword;
  a,b:array[1..1000] of char;
  f,s:array[0..1000,0..1,1..200] of qword;
  i,j,k,ki,ji,n,m:longint;
procedure p1;
begin
  assign(input,'substring.in');
  assign(output,'substring.out');
  reset(input);
  rewrite(output);
end;
procedure p2;
begin
  close(input);
  close(output);
end;
begin
  p1;
  readln(n,m,k);
  for i:=1 to n do read(a[i]);readln;
  for i:=1 to m do read(b[i]);readln;
  for i:=1 to n do begin
    if a[i]=b[1] then f[i,1,1]:=1 else f[i,1,1]:=0;
    s[i,1,1]:=s[i-1,1,1]+f[i,1,1];
  end;
  for j:=2 to m do
    for ki:=1 to k do begin
	  ji:=j and 1;
      for i:=0 to n do begin s[i,ji,ki]:=0;f[i,ji,ki]:=0;end;
	  for i:=j to n-m+j do begin
        if a[i]<>b[j] then f[i,ji,ki]:=0
        else begin  
	      if ki>1 then f[i,ji,ki]:=s[i-1,ji xor 1,ki-1];
          if a[i-1]=b[j-1] then f[i,ji,ki]:=(f[i,ji,ki]+f[i-1,ji xor 1,ki]) mod model;
	    end;
	    s[i,ji,ki]:=(s[i-1,ji,ki]+f[i,ji,ki]) mod model;
	  end;
	end;
  writeln(s[n,m and 1,k]);
  p2;
end.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值