zoukankan      html  css  js  c++  java
  • 【NOIP2015】子串

    本题在洛谷上的链接:https://www.luogu.org/problemnew/show/P2679


    好难的DP题,哎,今年要是遇到这样的DP题就放弃得了。。。

    本来打算像那道统计单词个数一样,先对字符串进行预处理,然后跑DP,想了个思路,复杂度很高,而且代码也不好实现。

    看大佬的博客里,用的方法类似LIS。就是讨论a中第i个字符取不取。

    定义状态dp[i][j][k][s],s=0表示所有的方案数,s=1表示必定取第i个字符的方案数。必须满足a[i]=b[j]才可以取第i个字符,此时dp[i][j][k][1]=dp[i-1][j-1][k-1][0]+dp[i-1][j-1][k][1],否则dp[i][j][k][1]=0;

    dp[i][j][k][0]自然就是dp[i-1][j][k][0]+dp[i][j][k][1],仔细想想的确是对的,但要自己想出来好难啊!

    虽然时间不会超,但空间会炸,需要滚动数组,因为我们发现第1维只用到了i和i-1,所以写成pre和now就好。

    再就是初始化dp[pre][0][0][0]=dp[now][0][0][0]=1,统计方案数的DP初始化最坑了,一般是把一种啥也不干的dp值设为1。

    最后别忘了对1e9+7取模。

     1 #include <cstdio>
     2 
     3 const int maxn = 1005, maxm = 205, maxk = 205, P = 1e9 + 7;
     4 
     5 int dp[2][maxm][maxk][2];
     6 
     7 char a[maxn], b[maxm];
     8 
     9 inline void swap(int &a, int &b) {
    10     int t = a; a = b, b = t;
    11 }
    12 
    13 int main() {
    14     int n, m, k, pre = 0, now = 1;
    15     scanf("%d%d%d%s%s", &n, &m, &k, a + 1, b + 1);
    16     dp[pre][0][0][0] = dp[now][0][0][0] = 1;
    17     for (int i = 1; i <= n; ++i, swap(pre, now))
    18         for (int j = 1; j <= m; ++j)
    19             for (int p = 1; p <= k; ++p) {
    20                 if (a[i] == b[j])
    21                     dp[now][j][p][1] = (dp[pre][j - 1][p - 1][0] + dp[pre][j - 1][p][1]) % P;
    22                 else dp[now][j][p][1] = 0;
    23                 dp[now][j][p][0] = (dp[pre][j][p][0] + dp[now][j][p][1]) % P;
    24             }
    25     printf("%d", dp[pre][m][k][0]);
    26     return 0;
    27 }
    AC代码
  • 相关阅读:
    心境的改变
    php之empty()函数常识性的错误
    php原生之实现图片,文件的下载
    多说,我还欠你一个会员
    开发模块化的初步理解
    Gradle模块化项目中使用了非模块化库的编译方法
    系统架构一一前端技术
    系统架构一一ORM的应用
    系统架构——依赖注入
    WPF下的RibbonApplicationMenu控件自定义
  • 原文地址:https://www.cnblogs.com/Mr94Kevin/p/9815345.html
Copyright © 2011-2022 走看看