NOIP2015 子串 dp
来源:互联网 发布:adobe pdf 电脑软件 编辑:程序博客网 时间:2024/06/05 16:50
【问题描述】
有两个仅包含小写英文字母的字符串 A 和 B。现在要从字符串 A 中取出 k 个互不重叠的非空子串,然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一 个新的字符串,请问有多少种方案可以使得这个新串与字符串 B 相等?注意:子串取出 的位置不同也认为是不同的方案。
【输入格式】
第一行是三个正整数 n,m,k,分别表示字符串 A 的长度,字符串 B 的长度,以及问题描述中所提到的 k,每两个整数之间用一个空格隔开。 第二行包含一个长度为 n 的字符串,表示字符串 A。 第三行包含一个长度为 m 的字符串,表示字符串 B。
【输出格式】
输出共一行,包含一个整数,表示所求方案数。由于答案可能很大,所以这里要求输出答案对 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
【数据范围】
对于第 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。
——————————————————————————————————————————————————————
第一要务,读懂题意然后方程就不会连样例都过不了了(不要问我为什么会这么说)。
这玩意儿算是把匹配和子集弄在一起了?
f(i,j,x)表示从A的前i个字符中选出x个不重叠的字符串拼接起来和B的前j个字符完全一样的方案数:
f(i,j,x)=f(i-1,j,x) + ( A[ii]==B[jj] ? f(ii-1,jj-1,x-1) : 0 ) , ii<=i,jj<=j , f(i,0,0)=1;
这样写下来就有个70分的样子了,复杂度O(N * M^2 * K),显然想要AC还是有点距离。
注意到方程中加号后面实际上是连续一串f的和(脑补一下状态表),所以就需要预处理一下,same[i][j]表示A的第i个字符和B的第j个字符作为结尾的最长连续子串的长度,sum[i][j][x]=f[i-1][j-1][x]+f[i-2][j-2][x]+……f[i-min(i,j)][j-min(i,j)][x],然后就可以把用前缀和把复杂度优化为 O(N * M * K),AC get!
same[i][j]= A[i]==B[j] ? same[i-1][j-1]+1 : 0
f(i,j,x)=f(i-1,j,x) + ( A[i]==B[j] ? sum[i-1][j-1][x-1]-sum[i-same[i][j]][j-same[i][j]][x-1]+f(i-same[i][j],j-same[i][j],x-1) : 0 );
注意到sum的下标如果写成sum[i-same[i][j]-1][j-same[i][j]-1][x-1]是有可能小于0的,所以保险起见写成上面的形式。
如果有更好的做法求求你告诉我ORZ!!!
AC代码:
#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<algorithm>#include<cmath>using namespace std;const int maxn=1005;const int maxm=205;const int mo=1000000007;char A[maxn],B[maxm];int N,M,K,f[maxn][maxm][maxm];int same[maxn][maxm],sum[maxn][maxm][maxm];void data_in(){ scanf("%d%d%d\n",&N,&M,&K); gets(A+1);gets(B+1);}void ready(){ for(int i=1;i<=N;i++) for(int j=1;j<=M;j++) same[i][j]= A[i]==B[j] ? same[i-1][j-1]+1 : 0;}void dp()//O(N*K*M){ for(int i=0;i<=N;i++) f[i][0][0]=1; for(int i=1;i<=N;i++) for(int x=1;x<=min(K,i);x++) { int upper=min(i,M); for(int j=1;j<=upper;j++) { f[i][j][x]=f[i-1][j][x]; if(A[i]==B[j]) f[i][j][x]=(((f[i][j][x]+sum[i-1][j-1][x-1])%mo -sum[i-same[i][j]][j-same[i][j]][x-1]+mo)%mo +f[i-same[i][j]][j-same[i][j]][x-1])%mo; sum[i][j][x]=(sum[i-1][j-1][x]+f[i][j][x])%mo; } }}void work(){ ready(); dp(); printf("%d\n",f[N][M][K]);}int main(){ freopen("test.in","r",stdin); freopen("test.out","w",stdout); data_in(); work(); return 0;}
- 【noip2015】【DP】子串
- NOIP2015 子串 DP
- noip2015 子串 dp
- NOIP2015 子串 dp
- [DP] NOIP2015 子串
- [noip2015]子串(dp)
- NOIP2015 子串【DP】【NOIP】
- 【uoj#149】【NOIP2015】子串 DP
- 【UOJ#149】【NOIP2015】子串【计数DP】
- NOIP2015 子串 解题报告(DP)
- [UOJ#149][NOIP2015]子串(dp)
- Noip2015 Day1 T2 子串(Dp)
- 洛谷 2676 [NOIP2015] 子串 DP
- UOJ149【NOIP2015】子串 (DP)
- 【DP】UOJ#149 【NOIP2015】子串
- [NOIP2015提高组]子串 DP
- code vs 4560 NOIP2015 D2T2 子串 (dp)
- 【codevs 4560】[NOIP2015 D2T2]子串(dp)
- 快来看看阿里巴巴的常用面试题
- 敦煌api 获取access_token和用户信息
- 自定义类型适配器的Gson工具类
- ubuntu source.list源不能用的情况下怎么做
- hive优化:让一个MR做更多的事情
- NOIP2015 子串 dp
- Android检查更新库CheckUpdateLibrary使用教程(一)
- javascript 浏览器之间跳转传递参数(不支持中文字符)
- 如何在.Net的C#中制作DLL文件,读取ini文件
- 详述 Java 中的别名现象 .
- 查看linux服务器的系统信息
- 青花器抓包
- 计算几何模板
- c++里求数组长度