【Luogu】P1410子序列(DP)

题目链接

我DP是真的菜啊啊啊啊啊!

f[i][j]表示考虑前i个数,有i-j+1个数组成一个上升子序列,且不以i结尾的尾端最小值。

设a为j个数组成的序列,且以i结尾;b为i-j+1个数组成的序列,且不以i结尾。

从f[i][j]到f[i+1][j+1]的转移如下:

若a后面可以接上第i+1个数,那b就和原来一样。也就是f[i+1][j+1]=min(f[i+1][j+1],f[i][j])

如果a后面不能接上第i+1个数,那就接到b上。也就是f[i+1][i-j+1]=min(f[i+1][i-j+1],que[i])

代码奉上

#include<cstdio>
#include<cctype>
#include<iostream>
#include<cstring>
using namespace std;
inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch==‘-‘)    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-‘0‘;
        ch=getchar();
    }
    return num*f;
}

int f[2020][2020];

int que[3000];
int n;
int main(){
    while(~scanf("%d",&n)){
        memset(f,127,sizeof(f));
        for(int i=1;i<=n;++i)    que[i]=read();
        f[1][1]=-1;
        for(int i=1;i<=n;++i)
            for(int j=1;j<=i;++j)
                if(f[i][j]!=f[0][0]){
                    if(que[i]<que[i+1])                        f[i+1][j+1]=min(f[i+1][j+1],f[i][j]);
                    if(f[i][j]<que[i+1])                f[i+1][i-j+1]=min(f[i+1][i-j+1],que[i]);
                }
        if(f[n][n>>1]==f[0][0])    printf("No!\n");
        else         printf("Yes!\n");
    }
    return 0;
}
时间: 2024-11-06 20:07:52

【Luogu】P1410子序列(DP)的相关文章

Luogu P1410 子序列

题目大意: 给定一个长度为\(N\)(\(N\)为偶数)的序列,] 问能否将其划分为两个长度为\(\frac{N}{2}\)的严格递增子序列, 输入一共有\(50\)组数据,每组数据保证\(N \leq 2*10^3\) 题目解法: 非常巧妙的一道\(DP\)题. $f[i][j] $ 表示到了第\(i\)个位置, 第一个序列中有\(j\)个元素,第二个序列中最后一个元素大小为\(f[i][j]\). 显然最小化\(f[i][j]\)是最优策略. 然后转移有两种: ( 1 )如果\(h[i]<h

HDU 1231 最大连续子序列 DP题解

典型的DP题目,增加一个额外要求,输出子序列的开始和结尾的数值. 增加一个记录方法,nothing special. 记录最终ans的时候,同时记录开始和结尾下标: 更新当前最大值sum的时候,更新开始节点. const int MAX_N = 10001; long long arr[MAX_N]; int N, sta, end; long long getMaxSubs() { long long sum = 0, ans = LLONG_MIN; int ts = 0; for (int

洛谷P1410 子序列

P1410 子序列 题目描述 给定一个长度为N(N为偶数)的序列,问能否将其划分为两个长度为N/2的严格递增子序列, 输入输出格式 输入格式: 若干行,每行表示一组数据.对于每组数据,首先输入一个整数N,表示序列的长度.之后N个整数表示这个序列. 输出格式: 同输入行数.对于每组数据,如果存在一种划分,则输出“Yes!”,否则输出“No!“. 输入输出样例 输入样例#1: 6 3 1 4 5 8 7 6 3 2 1 6 5 4 输出样例#1: Yes! No! 说明 [数据范围] 共三组数据,每

lis(最长上升子序列) dp

lis(最长上升子序列) dp 求序列的lis,子序列可不连续 for(int i=1;i<=N;i++){ scanf("%d",&a[i]); dp[i]=1; } for(int i=2;i<=N;i++){ for(int j=1;j<i;j++){ if(a[j]<a[i]) dp[i]=max(dp[i],dp[j]+1); } } int ans=1; for(int i=1;i<=N;i++){ //注意并不是dp[N]最大,而是要

Codeforces 10D LCIS 求最长公共上升子序列及输出这个子序列 dp

题目链接:点击打开链接 题意: 给定n长的一个序列 再给定k长的一个序列 求LCIS并输出这个子序列 如有多解输出任意解.. = - = 敲的时候听着小曲儿pre的含义还没有想清楚,万万没想到就过了... #include<stdio.h> #include<iostream> #include<string.h> #include<set> #include<vector> #include<map> #include<mat

HDU 1160 FatMouse&#39;s Speed (最長單調子序列 dp)

鏈接: http://acm.hdu.edu.cn/showproblem.php?pid=1160 Problem Description FatMouse believes that the fatter a mouse is, the faster it runs. To disprove this, you want to take the data on a collection of mice and put as large a subset of this data as pos

[算法模版]子序列DP

[算法模版]子序列DP 如何求本质不同子序列个数? 朴素DP 复杂度为\(O(nq)\).其中\(q\)为字符集大小. \(dp[i]\)代表以第\(i\)个数结尾的本质不同子序列个数.注意,这里对于每一个字符,只计算上一个相同字符带来的贡献.如果全部计算的话会算重复. 最后统计答案的时候也只统计每个字符最后一次出现的位置的答案. 例题:[线上训练13]子序列 中的50分部分分 #include<iostream> #include<cstdio> #include<cstr

洛谷 P1410 子序列(DP)

这题的题解的贪心都是错误的...正解应该是个DP 考虑有哪些有关的条件:两个序列的当前长度, 两个序列的末尾数, 把这些都压进状态显然是会GG的 考虑两个长度加起来那一位的数一定是其中一个序列的末尾, 而我们要末尾的数尽量小, 所以完全可以把这个DP缩成两维 设f[i][j]为当前选到第i位, a[i]选入第一个序列, 则末尾为a[i], 第一个序列长度为j, 则第二个序列长度为i-j时第二个序列末尾的数最小为多少. 则有 if(a[i]<a[i+1]) f[i+1][j+1]=min(f[i+

POJ-2533最长上升子序列(DP+二分)(优化版)

Longest Ordered Subsequence Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 41944   Accepted: 18453 Description A numeric sequence of ai is ordered if a1 < a2 < ... < aN. Let the subsequence of the given numeric sequence (a1, a2, ...