dp好题--2018.10.16模拟赛T1

2024-01-03 14:18
文章标签 16 dp 模拟 t1 好题 2018.10

本文主要是介绍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 &lt; = 50 , t&lt;=50, t<=50, n &lt; = 100000 n&lt;=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 i1 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的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/565968

相关文章

好题——hdu2522(小数问题:求1/n的第一个循环节)

好喜欢这题,第一次做小数问题,一开始真心没思路,然后参考了网上的一些资料。 知识点***********************************无限不循环小数即无理数,不能写作两整数之比*****************************(一开始没想到,小学没学好) 此题1/n肯定是一个有限循环小数,了解这些后就能做此题了。 按照除法的机制,用一个函数表示出来就可以了,代码如下

hdu4826(三维DP)

这是一个百度之星的资格赛第四题 题目链接:http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1004&cid=500 题意:从左上角的点到右上角的点,每个点只能走一遍,走的方向有三个:向上,向下,向右,求最大值。 咋一看像搜索题,先暴搜,TLE,然后剪枝,还是TLE.然后我就改方法,用DP来做,这题和普通dp相比,多个个向上

hdu1011(背包树形DP)

没有完全理解这题, m个人,攻打一个map,map的入口是1,在攻打某个结点之前要先攻打其他一个结点 dp[i][j]表示m个人攻打以第i个结点为根节点的子树得到的最优解 状态转移dp[i][ j ] = max(dp[i][j], dp[i][k]+dp[t][j-k]),其中t是i结点的子节点 代码如下: #include<iostream>#include<algorithm

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

hdu4865(概率DP)

题意:已知前一天和今天的天气概率,某天的天气概率和叶子的潮湿程度的概率,n天叶子的湿度,求n天最有可能的天气情况。 思路:概率DP,dp[i][j]表示第i天天气为j的概率,状态转移如下:dp[i][j] = max(dp[i][j, dp[i-1][k]*table2[k][j]*table1[j][col] )  代码如下: #include <stdio.h>#include

usaco 1.2 Transformations(模拟)

我的做法就是一个一个情况枚举出来 注意计算公式: ( 变换后的矩阵记为C) 顺时针旋转90°:C[i] [j]=A[n-j-1] [i] (旋转180°和270° 可以多转几个九十度来推) 对称:C[i] [n-j-1]=A[i] [j] 代码有点长 。。。 /*ID: who jayLANG: C++TASK: transform*/#include<

usaco 1.1 Broken Necklace(DP)

直接上代码 接触的第一道dp ps.大概的思路就是 先从左往右用一个数组在每个点记下蓝或黑的个数 再从右到左算一遍 最后取出最大的即可 核心语句在于: 如果 str[i] = 'r'  ,   rl[i]=rl[i-1]+1, bl[i]=0 如果 str[i] = 'b' ,  bl[i]=bl[i-1]+1, rl[i]=0 如果 str[i] = 'w',  bl[i]=b

uva 10154 DP 叠乌龟

题意: 给你几只乌龟,每只乌龟有自身的重量和力量。 每只乌龟的力量可以承受自身体重和在其上的几只乌龟的体重和内。 问最多能叠放几只乌龟。 解析: 先将乌龟按力量从小到大排列。 然后dp的时候从前往后叠,状态转移方程: dp[i][j] = dp[i - 1][j];if (dp[i - 1][j - 1] != inf && dp[i - 1][j - 1] <= t[i]

uva 10118 dP

题意: 给4列篮子,每次从某一列开始无放回拿蜡烛放入篮子里,并且篮子最多只能放5支蜡烛,数字代表蜡烛的颜色。 当拿出当前颜色的蜡烛在篮子里存在时,猪脚可以把蜡烛带回家。 问最多拿多少只蜡烛。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cs

uva 10069 DP + 大数加法

代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <queue>#include <map>#include <cl