博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
NOIP2015DAY2T2子串
阅读量:5890 次
发布时间:2019-06-19

本文共 2903 字,大约阅读时间需要 9 分钟。

描述

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

20170522100101_14084

【数据规模与约定】 对于第1组数据:1<=n<=500,1<=m<=50,k=1; 对于第2组至第3组数据:1<=n<=500,1<=m<=50,k=2; 对于第4组至第5组数据:1<=n<=500,1<=m<=50,k=m; 对于第1组至第7组数据:1<=n<=500,1<=m<=50,1<=k<=m; 对于第1组至第9组数据:1<=n<=1000,1<=m<=100,1<=k<=m; 对于所有10组数据:1<=n<=1000,1<=m<=200,1<=k<=m。

输入

输入文件名为substring.in。 第一行是三个正整数n,m,k,分别表示字符串A的长度,字符串B的长度,以及问 题描述中所提到的k,每两个整数之间用一个空格隔开。 第二行包含一个长度为n的字符串,表示字符串A。 第三行包含一个长度为m的字符串,表示字符串B。

输出

输出文件名为substring.out。 输出共一行,包含一个整数,表示所求方案数。由于答案可能很大,所以这里要求输 出答案对1,000,000,007取模的结果。

样例输入[复制]
样例1:
6 3 1
aabaab
aab
样例2:
6 3 2
aabaab
aab
样例3:
6 3 3
aabaab
aab
样例输出[复制]
样例1:
2
样例2:
7
样例3:
7
 
 
这道题我一开始看到也知道是dp,但是看到这个数据范围我就直接虚了
数组都开不下
但我暂时抛开这个东西不管,不计空间成本的话实际上状态是很容易出来的
首先有点基础知道这是个三维dp,状态f[i][j][k]代表A串前i个字符,已经匹配了B串j个字符,当前已经使用k次子串的方案数
显然貌似一个方程就出来了
对于当前的i,j来说,往后转移的条件显然是当前的a[i]==b[j],我们从最长公共子序列可以知道这一点
f[i][j][k]=f[i-1][j-1][k-1]+f[i-1][j-1][k]
这个式子的意思是当前的决策可以是单独成为一串,或者与前面的合并成一串
正如luogu里面的题解说的一样,这个方程的问题在于如果相等了就必须匹配进去,可能不使用后面也有选择,如果你不匹配直接沿用前面+f[i-1][j][k]的话会出现重复计数的问题(至少写完代码我是这么认为的,有错希望指正)
 
看完题解之后发现要设两个数组f[i][j][k]与s[i][j][k],第一个数组代表选或者不选当前的字符的方案数,第二个是必须选的方案数
 
为了分解问题我们先看s[i][j][k]的转移方法,当然前提还是a[i]=b[j]
s[i][j][k]由于必须要选进去,则只用考虑是单独成为一串或者是与前面连在一起
注意如果是前者因为前面的状态我不知道,我只知道我现在是用了一个字符单独成为一串,前面的用没用我不知道,所以应该是f[i-1][j-1][k-1],代表不确定性
后者由于与前面是连在一起的所以前面的也会被使用,所以应该是s[i-1][j-1][k]
总的下来方程就是
s[i][j][k]=f[i-1][j-1][k-1]+s[i-1][j-1][k]

显然如果a[i]!=b[j]的话直接s[i][j][k]就是0

接下来我们考虑f[i][j][k]的转移,前提还是一样的

由于我现在的决策已经变成了选或者不选的问题了,已经与匹不匹配无关了

如果我选择这个进行匹配的话,如果是使用当前的字符,我们就要加上一定使用这个字符的方案数s[i][j][k],如果你说我选上并不匹配怎么办?注意如果本身不匹配那么s[i][j][k]是0,选上没有意义

如果我们选择不用的话,自然就直接由上一个状态转移过来f[i-1][j][k]

方程就是

f[i][j][k]=s[i][j][k]+f[i-1][j][k]

为什么我们这个没有判断说是a[i]==b[j]?因为与匹配无关,我们关心的是选上去的方案数的贡献和不选的贡献,为什么我们不在s里面解决?因为选与不选是一个状态,自成一家或者与前面混合又是一个状态,两个状态不能混在一起!!

最后发现数组不够用啊,我们尝试滚掉一维

为什么我们能滚掉一维?因为在写循环的时候我们是按i作为第一维,而第一维i使用完之后只会对i+1做出贡献,就是背包问题,于是我们就复用数组

至于滚掉一维数组后后面的循环顺序就应该倒过来,因为你要用之前的状态,如果你正向就会用到刚算好的状态造成重复(这也是多重背包的原理),就可以覆盖前面

还是照例总结一下

这道题其实告诉我如果有多个不同的状态(红字)就应该尝试分开他们来进行讨论,不要固执于使用一个数组,这些状态是交融但是不完全等同的,应该及时分开处理

记得取模

代码在下面了:

1 #include
2 #include
3 using namespace std; 4 char a[100000],b[10000]; 5 int f[1000][1000]; 6 int s[1000][1000];const int mod=1000000007; 7 int main() { 8 int n,m,k; 9 cin>>n>>m>>k;10 for(int i=1; i<=n; i++)cin>>a[i];11 for(int i=1; i<=m; i++)cin>>b[i];12 f[0][0]=1;13 for(int i=1;i<=n;i++){14 for(int j=m;j>=1;j--){15 for(int l=k;l>=1;l--){16 if(a[i]==b[j])s[j][l]=f[j-1][l-1]+s[j-1][l];17 else s[j][l]=0;18 s[j][l]%=mod;19 f[j][l]=f[j][l]+s[j][l];20 f[j][l]%=mod;21 //cout<
<<" "<
<<" "<
<<" "<
<

一道好题啊

转载于:https://www.cnblogs.com/saionjisekai/p/9653320.html

你可能感兴趣的文章
【转】Java泛型-类型擦除
查看>>
PredictionIO+Universal Recommender快速开发部署推荐引擎的问题总结(2)
查看>>
【232】◀▶ IDL显示地理图像
查看>>
【116】Windows 系统组合键
查看>>
学习进度表 04
查看>>
python---__getattr__\__setattr_重载'.'操作
查看>>
谈谈javascript中的prototype与继承
查看>>
时序约束优先级_Vivado工程经验与各种时序约束技巧分享
查看>>
nginx win 启动关闭_windows下nginx启动与关闭的批处理脚本
查看>>
minio 并发数_MinIO 参数解析与限制
查看>>
eap wifi 证书_用openssl为EAP-TLS生成证书(CA证书,服务器证书,用户证书)
查看>>
mysql 应用程序是哪个文件夹_Mysql 数据库文件存储在哪个目录?
查看>>
mysql半同步和无损复制_MySQL半同步复制你可能没有注意的点
查看>>
mysql能看见表显示表不存在_遇到mysql数据表不存在的问题
查看>>
使用mysql实现宿舍管理_JSP+Struts2+JDBC+Mysql实现的校园宿舍管理系统
查看>>
mysql alter 修改字段类型_MySQL ALTER命令:删除,添加或修改表字段、修改字段类型及名称等...
查看>>
mysql中的事务和锁_MySQL - 事务和锁中的互斥?
查看>>
mysql statement讲解_Statement接口详解
查看>>
mysql_print_default_知识点:MySQL常用工具介绍(十 二)——实用程序my_print_defaults、perror...
查看>>
mysql怎么会报错_MySQL启动报错怎么办?
查看>>