关于序列DP问题的应用例题(包含:回文词、拦截导弹)

本人的第四篇博客,一早起来发现有7粉丝了!还挺意外的;

荣幸能够帮到大家,祝.好运连连~

问题一  回文词

例题  https://www.luogu.com.cn/problem/U454939

首先,对于任意一个字符串,我们该怎么知道它是不是回文词呢?

如    :ACDBA

不妨把它倒着写一遍

 变成:ABDCA

发现了吗,正着写和倒着写不一样,不是回文词

那该怎么改呢?

对于ACDBA来说,C和B出了问题,就像下面:

ACDBA

ABDCA

我们可以在前面、后面分别加上B、C,让它变成这样:

ABCDCBA

ABCDCBA

不难发现,我们不需要添加的部分就是他们的公共子序列,又因要求最少所以就是两个序列的最长公共子序列(神奇吧,又和DP扯上关系了)

既然这样,那需要添加的就是最长公共子序列以外序列的长度了

解决~

代码:
 

#include<bits/stdc++.h>
using namespace std;
long long n,ans,f[5001][5001];
char a[5001],b[5001];
int main(){
    scanf("%lld", &n);
    for(int i=1;i<=n;i++){
        scanf(" %c", &a[i]);
        b[n-i+1]=a[i];
    }
    memset(f,0,sizeof(f));
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(a[i]==b[j]) f[i][j]=f[i-1][j-1]+1;
            else f[i][j]=max(f[i-1][j],f[i][j-1]);
        }
    }
    printf("%lld\n", n-f[n][n]);
}

问题二  拦截导弹

P1020 [NOIP1999 提高组] 导弹拦截 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

翻译一下,就是让你求最长上升子序列,不一样的是,在中间还要顺手求一下最少的数量

将拦截的导弹的高度提出来成为原高度序列的一个子序列,根据题意这个子序列中的元素是单调不增的(即后一项总是不大于前一项),我们称为单调不升子序列。本问所求能拦截到的最多的导弹,即求最长的单调不升子序列

记 dp[i]​ 表示「对于前 i 个数,在选择第i 个数的情况下,得到的单调不升子序列的长度最长是多少」。于是可以分两种情况(这里演示的是一维代码):

  • 第 i 个数是子序列的第一项。则
  • 第 i 个数不是子序列的第一项。选择的第 i 个数之前选择了第 j 个数。
  • 根据题意,第 j 个数的值 h(j) 应当小于第 i 个数的值 h(i)。枚举这样的 j,可以得到状态转移方程:

综合这两种情况,得到最终的状态转移方程:

上代码:
 

#include<bits/stdc++.h>
#define up(l,r,i) for(int i=l,END##i=r;i<=END##i;++i)
#define dn(r,l,i) for(int i=r,END##i=l;i>=END##i;--i)
using namespace std;
typedef long long i64;
const int INF =2147483647;
const int MAXN=1e5+3;
int n,t,H[MAXN],F[MAXN];
int main(){
    while(~scanf("%d",&H[++n])); --n;
    t=0,memset(F,0,sizeof(F)),F[0]=INF;
    up(1,n,i){
        int l=0,r=t+1; while(r-l>1){
            int m=l+(r-l)/2;
            if(F[m]>=H[i]) l=m; else r=m;
        }
        int x=l+1;  // dp[i]
        if(x>t) t=x; F[x]=H[i];
    }
    printf("%d\n",t);
    t=0,memset(F,0,sizeof(F)),F[0]=0;
    up(1,n,i){
        int l=0,r=t+1; while(r-l>1){
            int m=l+(r-l)/2;
            if(F[m]<H[i]) l=m; else r=m;
        }
        int x=l+1;
        if(x>t) t=x; F[x]=H[i];
    }
    printf("%d\n",t);
    return 0;
}
  • 18
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值