P1091 [NOIP2004 提高组] 合唱队形(动态规划+LIS)

P1091 [NOIP2004 提高组] 合唱队形

Part1:链接:

点我就送屠龙宝刀[doge]

Part2:题目

在这里插入图片描述

Part3:思路

隔了这么久,屑人再次捡起了他的节操,洗了洗,然后开始续写他的苦逼dp之路了。

在这里插入图片描述
这道题我们可以用 LIS (Longest Increasing Subsequence,最长上升子序列) 来处理。

LIS代码:

///O(n^2)
///lis1[i]:当考虑前i个元素后能够产生的最长子序列的长度
for(int i=1; i<=n; i++)
{
    lis1[i]=1;
    for(int j=1; j<i; j++)
        if(a[i]>a[j]) lis1[i]=max(lis1[i],lis1[j]+1);  
        ///如果i位置上的数字大于j位置上的数字,此时要考虑
        ///加入对方的序列,还是保持自己的序列
}

我们从前到后求LIS,然后再由后至前求一遍LIS,将两个结果分别存储在两个不同的数组。

最后枚举中心位置,即如果以pos为中心,往左递减,往右递增,那么最多会有 (lis1[pos]+lis2[pos]-1) 个人。

减一的理由:lis1[pos]和lis2[pos]都会把pos位置的人列入考虑范围,所以减去重复的1。

最后让久违的「伊丽莎白」君为我们呈上代码。

在这里插入图片描述

Part4:AC代码

#include<iostream>
#include<map>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int a[105];
int lis1[105],lis2[105];
int main()
{
    int n;
    ios::sync_with_stdio(false);
    cin>>n;
    int ans=-1;
    for(int i=1; i<=n; i++) cin>>a[i];
    ///第一遍LIS,正序
    for(int i=1;i<=n;i++)
    {
        lis1[i]=1;
        for(int j=1;j<i;j++)
            if(a[i]>a[j]) lis1[i]=max(lis1[i],lis1[j]+1);
    }
    
    ///第二遍LIS,逆序
    for(int i=n;i>=1;i--)
    {
        lis2[i]=1;
        for(int j=n;j>i;j--)
            if(a[i]>a[j]) lis2[i]=max(lis2[i],lis2[j]+1);
    }
    for(int i=1;i<=n;i++) ans=max(ans,lis1[i]+lis2[i]-1);
    
    ///注意!!!!我们求得的是K,我们要的是n-k!!!
    cout<<n-ans<<endl;
    return 0;
}

今天是2021年6月7日,高考第一天。
鸡汤应该都喝饱了,我也说不出什么优美的语言。
那就祝愿各位活成自己的样子。

Part5:死宅时间!!!

取自《银魂——鬼道丸篇》

坂田银时:
有个器官比我的心脏还重要。虽然我看不见它,但是它确实在我的体内。
因为有它我才能站得直,就算步履蹒跚也能笔直往前走。
如果我不去的话,它可是会拦腰折断的, 我的灵魂它会拦腰折断的!比起心脏停止跳动,我更重视它!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值