码迷,mamicode.com
首页 > 其他好文 > 详细

Luogu P1410 子序列

时间:2018-02-02 20:10:00      阅读:84      评论:0      收藏:0      [点我收藏+]

标签:偶数   转移   序列   pre   using   amp   get   gis   can   

题目大意:

给定一个长度为\(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[i+1]\),那么\(i+1\)可以放入第一个序列:
\[f[i+1][j+1] = min(f[i+1][j+1]\ , \ f[i][j])\]
( 2 )如果\(f[i][j]<h[i+1]\),那么\(i+1\)可以放入第二个序列:
\[f[i+1][i+j-1] = min(f[i+1][i+j-1],h[i])\]
其实就是交换了第一个序列与第二个序列。

实现代码:

#include<bits/stdc++.h>
#define RG register
#define IL inline
#define _ 2005
#define INF 2147483640
using namespace std;

IL int gi(){
    RG int data = 0 , m = 1; RG char ch = 0;
    while(ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
    if(ch == '-'){m = 0; ch = getchar();}
    while(ch >= '0' && ch <= '9')
    {data = (data << 1) + (data << 3) + (ch ^ 48); ch = getchar(); }
    return ( m ) ? data : -data;
}

int f[_][_] , h[_] , n;

int main(){
    while(scanf("%d",&n) != EOF){
        for(RG int i = 1; i <= n; i ++)h[i] = gi();
        for(RG int i = 1; i <= n; i ++)
            for(RG int j = 0; j <= i; j ++)
                f[i][j] = INF;
        f[1][1] = -INF;
        for(RG int i = 1; i <= n; i ++)
            for(RG int j = 1; j <= i; j ++)
                if(f[i][j] != INF){
                    if(h[i] < h[i+1])
                        f[i+1][j+1] = min(f[i][j] , f[i+1][j+1]);
                    if(f[i][j] < h[i+1])
                        f[i+1][i-j+1] = min(f[i+1][i-j+1] , h[i]);
                }
        puts( (f[n][n/2]!=INF) ? "Yes!" : "No!" );
    }return 0;
}

Luogu P1410 子序列

标签:偶数   转移   序列   pre   using   amp   get   gis   can   

原文地址:https://www.cnblogs.com/GuessYCB/p/8406505.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!