【NOIP2015】子串
2015-11-15 14:41
169 查看
传送门
在赛场上这道题坑了我不少的时间……还是我太菜了,不过还好写出来了(可我还是被卡常了……90分,我优化了一下常数就过了……不开心),时间复杂度O(nmk)。
DP的思路很简单
f(k,i,j)表示分了k段,用了第一个串中的前i个数字,已经构成了第二个串的前j个的方案数
f(k,i,j)=⎧⎩⎨∑f(k−1,l,j−1)∑f(k−1,l,j−1)+f(k,i−1,j−1)当s1[i]==s2[j]且s1[i−1]!=s2[j−1]当s1[i]==s2[j]且s1[i−1]==s2[j−1]其中0<l<i其中0<l<i
第一个转移是独立开辟出一个部分的可能数,第二个是算上之前就已经分了k个部分后把第k个部分扩大的方案数。还是比较好理解的,当然f数组要滚动第一维,不然会爆内存。
我觉得这一道题的难度,都和当年乌龟棋在当时的难度差不多了。但这道题的70分算法O(nm2k)比较好写,所以拉不卡差距。
相信大家在看了我的状态转移之后能想出O(nmk)的方法。其实我们需要维护的就只是那一个∑用一个tmp数组保存一下就好了(详见代码)
代码
在赛场上这道题坑了我不少的时间……还是我太菜了,不过还好写出来了(可我还是被卡常了……90分,我优化了一下常数就过了……不开心),时间复杂度O(nmk)。
DP的思路很简单
f(k,i,j)表示分了k段,用了第一个串中的前i个数字,已经构成了第二个串的前j个的方案数
f(k,i,j)=⎧⎩⎨∑f(k−1,l,j−1)∑f(k−1,l,j−1)+f(k,i−1,j−1)当s1[i]==s2[j]且s1[i−1]!=s2[j−1]当s1[i]==s2[j]且s1[i−1]==s2[j−1]其中0<l<i其中0<l<i
第一个转移是独立开辟出一个部分的可能数,第二个是算上之前就已经分了k个部分后把第k个部分扩大的方案数。还是比较好理解的,当然f数组要滚动第一维,不然会爆内存。
我觉得这一道题的难度,都和当年乌龟棋在当时的难度差不多了。但这道题的70分算法O(nm2k)比较好写,所以拉不卡差距。
相信大家在看了我的状态转移之后能想出O(nmk)的方法。其实我们需要维护的就只是那一个∑用一个tmp数组保存一下就好了(详见代码)
代码
#include<cstdio> #include<cstring> typedef unsigned int LL; const LL MOD = 1000000007LL; const int MAXN = 1005; int n, m, K; LL f[2][MAXN][205]; LL tmp[2][MAXN][205]; char s1[MAXN], s2[MAXN]; LL ans = 0; int main() { scanf("%d%d%d", &n, &m, &K); scanf("%s%s", s1+1, s2+1); f[0][0][0] = 1; tmp[0][0][0] = 1; for(int i = 0; i <= n; i ++) tmp[0][i][0] = 1; for(int k = 1; k <= K; k ++) { memset(tmp[k&1], 0, sizeof (tmp[k&1])); memset(f[k&1], 0, sizeof (f[k&1])); for(int i = 1; i <= n; i ++) { for(int j = 1; j <= m; j ++) { if(s1[i] == s2[j]) { f[k&1][i][j] = tmp[(k+1)&1][i-1][j-1]; if(s1[i-1] == s2[j-1]) f[k&1][i][j] = (f[k&1][i][j] + f[k&1][i-1][j-1]) % MOD; if(f[k&1][i][j] >= MOD) f[k&1][i][j] -= MOD; } tmp[k&1][i][j] = (tmp[k&1][i][j] + f[k&1][i][j]) % MOD + tmp[k&1][i-1][j]; if(tmp[k&1][i][j] > MOD) tmp[k&1][i][j] -= MOD; } } } for(int i = 1; i <= n; i ++) ans = (ans + f[K&1][i][m]) % MOD; printf("%d\n", ans); return 0; }
相关文章推荐
- IOS 自适应布局效果(附代码)
- 树状数组求逆序对(小朋友排队 蓝桥杯)
- Android线程间通信(二):MessageQueue(上)
- struts.custom.i18n.resources——struts国际化
- Introduction to Machine Learning (一)
- Chrome神器Vimium快捷键学习记录
- matlab安装后不能使用,问题提示如下:runtime error!
- GEOS库的学习之一:介绍和编译
- C#反射的坑
- PHP判断数组Array的维度(已封装函数)
- 数据包从源主机到达目标主机的过程。【转】
- linux网络编程常用头文件
- windows cmd 编码
- OC中对象的description方法
- hdu -4325-Flowers(离散化 线段树)
- MSMQ消息队列,一个按钮发送,一个按钮接受
- JAVASE---static关键字
- Matlab学习历程
- 从今天起,开启博客
- Linux常用命令