最小单调子序列的长度+联通最小乘积
因为题目ICPC是英文版,基于大家都不怎么看的懂的情况下直接给大家进行题目讲解
题目1:
题目分析:
构造一个长度为n的排列 p(里面的数是1-n),不能重复得 max(lis(p),lds(p)) 最小。
其中,lis(p)是 p 的最长递增子序列长度,lds(p) 是 p 的最长递减子序列长度。
排列:由 1 到 n 的整数组成的序列,每个整数恰好出现一次。例如,[2,3,1,5,4]是一个排列,但[1,2,2] 不是(重复出现 2),[1,3,4] 也不是(包含超出范围的数 4)。
问题正式描述:
设排列 p 的值为 max(lis(p),lds(p)),其中:
-
lis(p) 表示 p 的最长递增子序列(LIS)的长度,
-
lds(p) 表示 p 的最长递减子序列(LDS)的长度。
对于所有长度为 n的排列,你需要构造一个排列 p,使得其值(即 LIS 和 LDS 长度的最大值)最小。
递增子序列(Increasing Subsequence):若序列 a 可以通过删除序列 b 中的若干元素(可能为零或全部)得到,且 a 中的元素从头到尾严格递增,则称 a 是 b 的递增子序列。
递减子序列(Decreasing Subsequence):类似地,若 a 中的元素从头到尾严格递减,则称其为 b 的递减子序列。
思路讲解:
当n=3时,如何保证我们的递增子序列和递减子序列在所有的序列的情况当中最小呢,我们可以模拟一下来试试,其实感觉和规律很重要
当我们正常排列的时候发现这种的序列长度最长,但是题目是要一个最小的,应该怎么办呢
根据上图,我们这样排列,最长上升子序列的长度为3,最长下降子序列的长度也为0,这个情况下得到的max(lis(p),lds(p))最大为2,根据样例,说明我们这种排列一定是错误的,那我们来分析一下样例中的输出样例吧
根据上图,由此可见,这个情况下得到的max(lis(p),lds(p))最小,因为最长上升子序列的长度为2,最长下降子序列的长度也为2,符合条件
到这里大家应该明白了题目的意思,那么我们应该如何进行排列得到最小的值呢,当n变大时,怎么排呢?其实这里大家也可以去找规律,如果不太了解这样的情况,可以一个一个试试,去找合适并且有规律的最好形式
4 21 43
5 321 54
6 321 654
...
9 321 654 987
10 4321 8765 109
想必大家到这里一定有答案了,没错,就是每次让长度为平方根加1,然后进行反转,平方根是关键,通过4和9大家就可以清楚的了解
这道题主要就是思考过程,解答出来时很容易的,如果大家最开始没有思路,应该多想想这道题的目的,而且确实是一个有规律的题,毕竟是要用代码进行来实现的,大家遇到这种没有思路题就可以去模拟过程,有时候确实很好用
代码实现:
#include<bits/stdc++.h>
using namespace std;
int main(){int n;cin>>n;while(n--){int m;cin>>m;int a=ceil(sqrt(m));for(int i=1;i<=a;i++){int tmp=a*i;while(tmp>(i-1)*a){if(tmp<=m) cout<<tmp<<" ";tmp--;}}cout<<endl;}return 0;
}
题目2:
思路分析:
这个不是英文版的不做解释了大家直接看题吧
实现根据题目要求,我们要联通所有的块,就是说我们每个至少连接到一个,一个也可以连多个,题目说要得到最小值,我们这里就分三种情况(让0放到正数里面)
1.有正数也有负数 (让所有正数×所有负数)
2.只有正数(让最小的正数×其他正数)
3.只有负数(让最大负数×其他负数)
代码实现:
#include<bits/stdc++.h>
using namespace std;
int main(){int n;long long a=0,b=0; //a 正 b 付 int maxb=-1010,mina=1010;//maxb 负数中最大 mina 证书最大值 cin>>n;for(int i=0;i<n;i++){int j;cin>>j;if(j<0) {b += j;maxb=max(maxb,j);}else {a += j;mina=min(mina,j);} }if(a>0&&b<0) cout<<a*b;else if(a==0&&b<0) cout<<(b-maxb)*maxb;else cout<<(a-mina)*mina;return 0;
}