Description:
Wozuinb非常喜欢打炉石传说,但是菜的不行,所以他决定打竞技场来练练手。系统按顺序给出n张卡牌,每张卡牌都有自己的使用消耗a[i],每次只给出一张,wozuinb可以选择或者弃掉这张牌。每选择一张牌都会按选择顺序放在卡槽中,当
卡槽中放满30张即可组成一套套牌。Wozuinb希望自己的套牌的消耗满足一个平滑的曲线,即30张卡牌都满足第i张卡牌的消耗不小于第 i−1张( i>1)。请你帮助wozuinb看一看,这些卡牌能不能组成想要的套牌,如果能组成输出“yes”,如果不能输出“no”。
Input:
第一行输入一个整数n, 0<n<100。
第二行输入一行数字a[i],每个数字用空格隔开,代表第i张出现的卡牌的消耗。
Output:
输出一行,“yes”或“no”
Sample Input:
5
1 2 3 4 5
Sample Output:
no
题目链接
O(n^2)算法求最长不下降子序列
用lis[i]数组存储从第1个数到第i个数的最长不下降子序列,lis[i]便可以通过lis[i-1]求得
AC代码:
#include <stdio.h>
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
#include <iomanip>
#include <cctype>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long ll;
// O(n^2)算法求最长不下降子序列
ll n,a[110],lis[110]; // n为序列长度,a数组存序列,lis数组保存第1~i元素中最长不下降子序列的长度
int main() {
// 加速输入输出
ios::sync_with_stdio(0);
cin.tie(0);
// 输出序列长度
cin >> n;
// 依次输入序列各元素
for (int i = 1;i <= n;++i) {
cin >> a[i];
}
// 循环依次求1~i中最长不下降子序列的长度
for (int i = 1;i <= n;++i) {
// 将lis[i]初始化为1,因为至少有它本身
lis[i] = 1;
// 循环1~i中求已求出最长不下降子序列的最大值
for (int j = 1;j < i;++j) {
// 判断序列中第i个元素是否不小于(如果题目要求大于则将>=改为>)第j个元素,并且lis[j]加上第i个元素后是否大于lis[i]
if (a[i] >= a[j] && lis[j] + 1 > lis[i]) {
lis[i] = lis[j] + 1; // 更新lis[i]
}
}
}
// 循环遍历求lis数组中的最大值
int len = 0;
for (int i = 1;i <= n;++i) {
if (lis[i] > len) {
len = lis[i];
}
}
// 判断是否符合要求组成一套套牌,并按要求输出
if (len >= 30) {
cout << "yes" << endl;
}
else {
cout << "no" << endl;
}
return 0;
}
O(nlogn)算法求最长不下降子序列长度
从第一个数开始数,如果遇到大于等于已添加队列内队尾数的数就添加至队尾,否则替换掉已添加队列内第一个大于它的数,循环遍历计数得到结果。
AC代码:
#include <stdio.h>
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
#include <iomanip>
#include <cctype>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long ll;
// O(nlogn)算法求最长不下降子序列长度
int n,a[40005],d[40005]; // n为序列长度,a数组为输入原始序列,d[k]表示长度为k的不下降子序列末尾元素的最小值(d数组为单调数组(不会减小(可以相等)))
int main() {
// 加速输入输出
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n; // 输入序列长度
// 依次输入序列中n个元素
for (int i = 1;i <= n;++i) {
cin >> a[i];
}
d[1] = a[1];
int len = 1; // len表示当前已知的最长子序列的长度(0个元素的时候特判)
// 现在已知最长不下降子序列长度为1,末尾元素的最小值为序列中第一个元素(a[1])
// 从2~n循环依次求出前i个元素的最长不下降子序列的长度
for (int i = 2;i <= n;++i) {
// 考虑新进来一个元素a[i]
if (a[i] >= d[len]) { // 如果这个元素大于等于d[len](如果要求序列严格递增(不能相等)则把>=改为>)
d[++len] = a[i]; // 直接让这个元素排到后面
}
else { // 如果这个元素小于d[len],则a[i]应该替换掉d[len]数组中第一个大于a[i]的元素
int j = upper_bound(d + 1, d + len + 1, a[i]) - d; // 用STL upper_bound 找出d[len]中第一个大于a[i]的元素
d[j] = a[i]; // 替换掉
}
}
// 判断是否符合要求组成一套套牌,并按要求输出
if (len >= 30) {
cout << "yes" << endl;
}
else {
cout << "no" << endl;
}
return 0;
}