本文主要是介绍dp好题--2018.10.16模拟赛T1,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
题目大意:
多组数据,先给 t t t表示数据组数,给一个 1 1 1到 n n n的排列,问是否可以变成一个上升序列和一个下降序列拼起来,并输出上升序列的长度以及这个上升序列,下降序列同理。(语文不太好···
给个样例就是:
输入:
3
5
5 1 4 2 3
5
1 2 3 5 4
1
1
输出:
YES
2 1 2
3 5 4 3
YES
3 1 2 3
2 5 4
YES
0
1 1
数据范围: t < = 50 , t<=50, t<=50, n < = 100000 n<=100000 n<=100000
solution:
第一眼看到这个数据范围就想到了贪心什么的···
反正差不多是 O ( N ) O(N) O(N)做,也想过 d p dp dp,但感觉用一般的 d p dp dp很不现实
所以就想贪心,但是这个题贪心是错的
真的是 d p dp dp啊我还是太 n a i v e naive naive了
但是要考虑 d p dp dp状态如何设计,果然不是一般的 d p dp dp状态
也不是 l i s lis lis不要想多了
设 d p [ i ] dp[i] dp[i]表示以 i i i为上升序列的结尾,最大的下降序列结尾(值)是什么
可以这样设计是因为,已经知道了这个序列一定是由上升和下降序列构成的,所以只要考虑一个的状态,在这个状态下让另一个更优就一定会找到可行解。
然后考虑转移,首先他能 O ( n 2 ) 做 , O(n^2)做, O(n2)做,有一个 O ( n l o g n ) O(nlogn) O(nlogn)的方法就是线段树优化前缀最大值 e m m m emmm emmm十分暴力很卡常
一个很厉害的 O ( n ) d p O(n)dp O(n)dp就是考虑大力分类讨论, p r e [ i ] pre[i] pre[i]记录上升序列的前一个的下标方便输出,还要记录一个 m v mv mv表示如果 i − 1 i-1 i−1和 i i i不在一个上升序列时前面可以接上 i i i的
这么说不太直观还是看代码吧 q w q qwq qwq
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define maxn 100005
using namespace std;
int t,n,a[maxn],dp[maxn],pre[maxn]; bool used[maxn];
inline int rd(){int x=0,f=1;char c=' ';while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();return x*f;
}
int main(){freopen("quin.in","r",stdin);freopen("quin.out","w",stdout);t=rd();while(t--){n=rd();for(int i=1;i<=n;i++) a[i]=rd();a[n+1]=n+2; dp[0]=n+1;int mv=0;for(int i=1;i<=n+1;i++){dp[i]=-1;//记得初始化! if(a[i-1]<a[i]) dp[i]=dp[i-1],pre[i]=i-1;//i和i-1组成上升if(mv!=-1 && a[mv]<a[i] && a[i-1]>dp[i]) dp[i]=a[i-1],pre[i]=mv;//i和mv组成上升if(i!=1 && a[i-1]<a[i]) mv=-1;//重新找上升的结尾 if(dp[i-1]>a[i] && (mv==-1||a[mv]>a[i-1]))mv=i-1;//i可以作为下降的结尾,i-1为上升结尾 }if(dp[n+1]==-1){puts("NO"); continue;}memset(used,0,sizeof used);puts("YES");int u=n+1,tot=0;while(u!=0) used[u]=1,u=pre[u];//找出上升的 for(int i=1;i<=n;i++)if(used[i]) tot++;printf("%d ",tot);for(int i=1;i<=n;i++)if(used[i]) printf("%d ",a[i]);printf("\n%d ",n-tot);for(int i=1;i<=n;i++)if(!used[i]) printf("%d ",a[i]); printf("\n");}return 0;
}
这篇关于dp好题--2018.10.16模拟赛T1的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!