Noip 2015 子串(洛谷P2679)
来源:互联网 发布:c语言求最大公因数函数 编辑:程序博客网 时间:2024/05/18 01:44
题目描述
有两个仅包含小写英文字母的字符串 A 和 B。
现在要从字符串 A 中取出 k 个互不重叠的非空子串,然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一 个新的字符串,
请问有多少种方案可以使得这个新串与字符串 B 相等?
注意:子串取出 的位置不同也认为是不同的方案。
输入输出格式
输入格式:
输入文件名为 substring.in。
第一行是三个正整数 n,m,k,分别表示字符串 A 的长度,字符串 B 的长度,以及问题描述中所提到的 k,每两个整数之间用一个空格隔开。
第二行包含一个长度为 n 的字符串,表示字符串 A。 第三行包含一个长度为 m 的字符串,表示字符串 B。
输出格式:
输出文件名为 substring.out。 输出共一行,包含一个整数,表示所求方案数。
由于答案可能很大,所以这里要求输出答案对 1,000,000,007 取模的结果。
输入输出样例
输入样例#1:
6 3 1
aabaab
aab
输出样例#1:
2
输入样例#2:
6 3 2
aabaab
aab
输出样例#2:
7
输入样例#3:
6 3 3
aabaab
aab
输出样例#3:
7
对于第 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。
这是我见过的题中,代码长度与思维难度比例差距最大的一道神题!
代码真的短的惊人,但是思维难度真的不是一般的大。
首先这一看就是一道动态规划吧。
第一眼看到这题的时候,想到的DP式子是这样的:
dp[ i ][ j ][ k ]代表A串位置到了 i ,B串到了 j ,已经用了 k 个子串。
自然想到: dp[ i ][ j ][ k ] = dp[ i-1 ][ j-1 ][ k ] + dp[ i-1 ][ j-1 ][ k-1 ]; ( A[i] == B[j] )
即:能匹配时,方案数为:单独使用当前字符为一个子串 + 与前面相连形成一个子串;
稍微仔细一想就可以知道,这个DP式子是有问题的。
如果不使用当前字符,情况是什么样的呢?貌似被默默的遗漏了耶……
所以我们就要分开来设了。
设s[ i ][ j ][ k ]为A用到了 i ,B用到了 j ,已经用了 k 个子串, 并且一定用了当前字符(A[i])时的方案数。
设f[ i ][ j ][ k ]为A用到了 i ,B用到了 j ,已经用了 k 个子串, 无论用不用当前字符(A[i])时的方案数总和。
接下来这个转移可就有蛮难想了。
一个一个来,
先分析一下 s 的转移。
能转移的前提自然是 A[ i ] == B [ j ]啦。
既然 A[i] 一定要用,那么依旧是两种情况:独自成一串 或 与前面的成一串。
独自成一串,方案数为:f[ i-1 ][ j-1 ][ k-1]
与前方共成一串,方案数为:s[ i-1 ][ j-1 ][ k ],因为前一个字符串(A[i-1])也一定要用!
所以合并一下: s[ i ][ j ][ k ] = f[ i-1 ][ j-1 ][ k-1 ] + s[ i-1 ][ j-1 ][ k ];
接着分析 f 的转移。
f[ i ][ j ][ k ] 的来源也有两种: 使用当前字符 或 不使用当前字符
对于使用当前字符,方案数算法如上,答案即:s[ i ][ j ][ k ];
对于不使用当前字符,则从f[ i-1 ]转来,即:f[ i -1 ][ j ][ k ];
合并一下: f[ i ][ j ][ k ] = f[ i-1 ][ j ][ k ] + s[ i ][ j ][ k ];
所以将两个合并一下子,就得到:
-->对于每一个i , j , k :if( A[i] == B[j] )s[i][j][k] = f[i-1][j-1][k-1] + s[i-1][j-1][k];else s[i][j][k] = 0;f[i][j][k] = f[i-1][j][k] + s[i][j][k];
答案存在f[ n ][ m ][ k ]中,显然边界条件为 f[ i ][ 0 ][ 0 ] = 1;
到这里这道题就做完了。
别看上面说的顺溜溜的,笔者做的时候整个脑子都是混乱的!。
当然直接开O(n*m*k)的数组是肯定开不下的,第一维的 i 显然可以滚掉(对于提高组大佬这肯定是so easy 啦)。
下面是具体实现代码:
#include<bits/stdc++.h>#define mod 1000000007using namespace std;int a,b,k;char A[1002],B[1002];int f[3][1000][1000],s[3][1000][1000];int main(){ scanf("%d%d%d\n",&a,&b,&k); scanf("%s",A+1); scanf("%s",B+1); int now=1,past=0; f[0][0][0]=1; for(int e=1;e<=a;e++){ f[now][0][0]=1; for(int j=1;j<=b;j++){ for(int t=1;t<=k;t++){ if(A[e]==B[j])s[now][j][t]=(s[past][j-1][t]+f[past][j-1][t-1])%mod; else s[now][j][t]=0; f[now][j][t]=(f[past][j][t]+s[now][j][t])%mod; } }swap(now,past); } cout<<f[past][b][k]; return 0;}
- Noip 2015 子串(洛谷P2679)
- Luogu P2679 [NOIp提高组2015]子串
- 洛谷 P2679 子串
- 洛谷 P2679子串
- 洛谷P2679 子串(NOIP2015)
- 洛谷P2679 NOIP2015 子串
- P2679子串(dp)
- 洛谷 P2679 [NOIP2015 D2T2] 子串
- dp——洛谷P2679子串
- NOIP 2015 子串
- NOIP 2015 子串 (DP)
- NOIP 2015 子串 DP
- Noip 2015 D2T2 子串(动态规划)
- NOIP 2015 Day 2 substring 子串(字符串 dp)
- NOIP 2015 D2 T2 子串 substring
- [抄][1]NOIP 2015 子串
- 【NOIp 2015】【动态规划】子串
- 【Noip 2015】 子串 解题报告
- JSP中页面的转发与重定向
- 关于解决NX重置之后“试图使用不活动的对象”
- IO流 3
- XML文件在Eclipse中报黄色警号No grammar constraints (DTD or XML Schema) referenced in the document.
- JavaScript中的立即执行函数
- Noip 2015 子串(洛谷P2679)
- 射击(递归)
- HDU 5036 Explosion
- XML在Eclipse中报"Stream not available"警告
- linux ubuntu中boot无存储空间解决办法
- bzoj 2150: 部落战争 最小路径覆盖的做法+证明。
- MySQL数据库安装与配置详解
- HDU-6052 card card card(尺取法)
- C语言用法之extern