热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

NOIP2015DAY2T2子串

描述有两个仅包含小写英文字母的字符串A和B。现在要从字符串A中取出k个互不重叠的非空子串,然后把这k个子串按照其在字符串A中出现的顺序依次连接起来得到一个新的字符串&
描述

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

20170522100101_14084

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

输入

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

输出

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

样例输入[复制]
样例1&#xff1a;
6 3 1
aabaab
aab

样例2&#xff1a;
6 3 2
aabaab
aab

样例3&#xff1a;
6 3 3
aabaab
aab
样例输出[复制]
样例1&#xff1a;
2

样例2&#xff1a;
7

样例3&#xff1a;
7
这道题我一开始看到也知道是dp&#xff0c;但是看到这个数据范围我就直接虚了
数组都开不下
但我暂时抛开这个东西不管&#xff0c;不计空间成本的话实际上状态是很容易出来的
首先有点基础知道这是个三维dp&#xff0c;状态f[i][j][k]代表A串前i个字符&#xff0c;已经匹配了B串j个字符&#xff0c;当前已经使用k次子串的方案数
显然貌似一个方程就出来了
对于当前的i,j来说&#xff0c;往后转移的条件显然是当前的a[i]&#61;&#61;b[j]&#xff0c;我们从最长公共子序列可以知道这一点

f[i][j][k]&#61;f[i-1][j-1][k-1]&#43;f[i-1][j-1][k]

这个式子的意思是当前的决策可以是单独成为一串&#xff0c;或者与前面的合并成一串
正如luogu里面的题解说的一样&#xff0c;这个方程的问题在于如果相等了就必须匹配进去&#xff0c;可能不使用后面也有选择&#xff0c;如果你不匹配直接沿用前面&#43;f[i-1][j][k]的话会出现重复计数的问题&#xff08;至少写完代码我是这么认为的&#xff0c;有错希望指正&#xff09;
看完题解之后发现要设两个数组f[i][j][k]与s[i][j][k]&#xff0c;第一个数组代表选或者不选当前的字符的方案数&#xff0c;第二个是必须选的方案数
为了分解问题我们先看s[i][j][k]的转移方法&#xff0c;当然前提还是a[i]&#61;b[j]
s[i][j][k]由于必须要选进去&#xff0c;则只用考虑是单独成为一串或者是与前面连在一起
注意如果是前者因为前面的状态我不知道&#xff0c;我只知道我现在是用了一个字符单独成为一串&#xff0c;前面的用没用我不知道&#xff0c;所以应该是f[i-1][j-1][k-1],代表不确定性
后者由于与前面是连在一起的所以前面的也会被使用&#xff0c;所以应该是s[i-1][j-1][k]
总的下来方程就是

s[i][j][k]&#61;f[i-1][j-1][k-1]&#43;s[i-1][j-1][k]

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

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

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

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

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

方程就是

f[i][j][k]&#61;s[i][j][k]&#43;f[i-1][j][k]

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

最后发现数组不够用啊&#xff0c;我们尝试滚掉一维

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

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

还是照例总结一下

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

记得取模

代码在下面了&#xff1a;

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&#61;1000000007;
7 int main() {
8 int n,m,k;
9 cin>>n>>m>>k;
10 for(int i&#61;1; i<&#61;n; i&#43;&#43;)cin>>a[i];
11 for(int i&#61;1; i<&#61;m; i&#43;&#43;)cin>>b[i];
12 f[0][0]&#61;1;
13 for(int i&#61;1;i<&#61;n;i&#43;&#43;){
14 for(int j&#61;m;j>&#61;1;j--){
15 for(int l&#61;k;l>&#61;1;l--){
16 if(a[i]&#61;&#61;b[j])s[j][l]&#61;f[j-1][l-1]&#43;s[j-1][l];
17 else s[j][l]&#61;0;
18 s[j][l]%&#61;mod;
19 f[j][l]&#61;f[j][l]&#43;s[j][l];
20 f[j][l]%&#61;mod;
21 //cout<
22 }
23 }
24 }
25 cout<<f[m][k];
26 return 0;
27 }

一道好题啊


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


推荐阅读
  • 本文针对HDU 1042 N! 问题提供详细的解析和代码实现。题目要求计算给定整数N(0 ≤ N ≤ 10000)的阶乘N!。文章不仅提供了算法思路,还附上了C++语言的具体实现。 ... [详细]
  • 本文探讨了Linux环境下线程私有数据(Thread-Specific Data, TSD)的概念及其重要性,介绍了如何通过TSD技术避免多线程间全局变量冲突的问题,并提供了具体的实现方法和示例代码。 ... [详细]
  • hlg_oj_1116_选美大赛这题是最长子序列,然后再求出路径就可以了。开始写的比较乱,用数组什么的,后来用了指针就好办了。现在把代码贴 ... [详细]
  • 页面预渲染适用于主要包含静态内容的页面。对于依赖大量API调用的动态页面,建议采用SSR(服务器端渲染),如Nuxt等框架。更多优化策略可参见:https://github.com/HaoChuan9421/vue-cli3-optimization ... [详细]
  • 汇总了2023年7月7日最新的网络安全新闻和技术更新,包括最新的漏洞披露、工具发布及安全事件。 ... [详细]
  • 本文详细介绍如何在SSM(Spring + Spring MVC + MyBatis)框架中实现分页功能。包括分页的基本概念、数据准备、前端分页栏的设计与实现、后端分页逻辑的编写以及最终的测试步骤。 ... [详细]
  • 在使用 PyInstaller 将 Python 应用程序打包成独立的可执行文件时,若项目中包含动态加载的库或插件,需要正确配置 --hidden-import 和 --add-binary 参数,以确保所有依赖项均能被正确识别和打包。 ... [详细]
  • 笔记说明重学前端是程劭非(winter)【前手机淘宝前端负责人】在极客时间开的一个专栏,每天10分钟,重构你的前端知识体系& ... [详细]
  • 本文详细介绍如何安装和配置DedeCMS的移动端站点,包括新版本安装、老版本升级、模板适配以及必要的代码修改,以确保移动站点的正常运行。 ... [详细]
  • 本文详细介绍了如何在 Ubuntu 14.04 系统上搭建仅使用 CPU 的 Caffe 深度学习框架,包括环境准备、依赖安装及编译过程。 ... [详细]
  • 想把一组chara[4096]的数组拷贝到shortb[6][256]中,尝试过用循环移位的方式,还用中间变量shortc[2048]的方式。得出的结论:1.移位方式效率最低2. ... [详细]
  • 本文详细介绍如何在 Apache 中设置虚拟主机,包括基本配置和高级设置,帮助用户更好地理解和使用虚拟主机功能。 ... [详细]
  • Vue CLI 基础入门指南
    本文详细介绍了 Vue CLI 的基础使用方法,包括环境搭建、项目创建、常见配置及路由管理等内容,适合初学者快速掌握 Vue 开发环境。 ... [详细]
  • 网络流24题——试题库问题
    题目描述:假设一个试题库中有n道试题。每道试题都标明了所属类别。同一道题可能有多个类别属性。现要从题库中抽取m道题组成试卷。并要求试卷包含指定类型的试题。试设计一个满足要求的组卷算 ... [详细]
  • 本文详细介绍了在 Red Hat Linux 系统上安装 GCC 4.4.2 的步骤,包括必要的依赖库的安装及常见问题的解决方法。 ... [详细]
author-avatar
钟杰辉_576
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有