Beauty Of Unimodal Sequence(HDU-6592)
Problem Description
You are given an array of n integers a1,a2,...,an. We define that a sequence p1,p2,...,pk(k∈[1,n]) is beautiful if and only if these conditions are met:
- 1≤p1<p2<⋯<pk≤n.
- There exists t(t∈[1,k]) satisfying ap1<ap2<⋯<apt and apt>apt+1>⋯>apk.
You need to find all the longest beautiful sequences, and output the lexicographically smallest one and the lexicographically largest one in them.
Check the examples below for better understanding.Input
There are multiple test cases.
Each case starts with a line containing a positive integer n(n≤3×105).
The second line contains n integers a1,a2,...,an(1≤ai≤109).
It is guaranteed that the sum of Ns in all test cases is no larger than 106.Output
For each test case, output two lines, the first of which depicts the lexicographically smallest one in longest beautiful sequences and the second of which depicts the lexicographically largest one in longest beautiful sequences.
Sample Input
7
1 4 2 5 7 4 6
3
1 2 3
3
3 2 1Sample Output
1 2 4 5 6
1 3 4 5 7
1 2 3
1 2 3
1 2 3
1 2 3
题意:t 组数据,每组给出一个长度为 n 的序列 a,求序列 a 的最长的字典序最小的单峰子序列、最大的单峰子序列
思路:
由于要求一个单峰子序列,那么可以正反各求一遍最长上升子序列 LIS,然后进行模拟来寻找单峰子序列
求字典序最小时,首先找到第一个峰,然后利用单调栈从后向前找递减的序列中下标较小的,再向后找严格递减的
求字典序最大时,首先找到最大的一个峰,然后从后向前依次找严格递减的,再向后找 LIS 中下标大的
Source Program
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<unordered_map>
#include<bitset>
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define LL long long
#define Pair pair<LL,LL>
LL quickPow(LL a,LL b){ LL res=1; while(b){if(b&1)res*=a; a*=a; b>>=1;} return res; }
LL quickModPow(LL a,LL b,LL mod){ LL res=1; a=a%mod; while(b){if(b&1)res=(a*res)%mod; a=(a*a)%mod; b>>=1;} return res; }
LL getInv(LL a,LL mod){ return quickModPow(a,mod-2,mod); }
LL GCD(LL x,LL y){ return !y?x:GCD(y,x%y); }
LL LCM(LL x,LL y){ return x/GCD(x,y)*y; }
const double EPS = 1E-10;
const int MOD = 998244353;
const int N = 500000+5;
const int dx[] = {-1,1,0,0,1,-1,1,1};
const int dy[] = {0,0,-1,1,-1,1,-1,1};
using namespace std;
int a[N],pos1[N],pos2[N];
int dp[N];
int pos[N];
void getLIS(int n){
//正着求一遍LIS
memset(dp,INF,sizeof(dp));
dp[0]=0;
for(int i=1; i<=n; i++) { //正着求一遍LIS
pos1[i] = lower_bound(dp+1, dp+n+1, a[i])-dp;
dp[pos1[i]]=a[i];
}
//反着求一遍LIS
memset(dp,INF,sizeof(dp));
dp[0]=0;
for(int i=n;i>0;i--){
pos2[i]=lower_bound(dp+1, dp+n+1, a[i])-dp;
dp[pos2[i]]=a[i];
}
}
vector<int> getSmallLEX(int n){
int index=1;//记录下标
int maxx=pos1[1]+pos2[1];
for(int i=2; i<=n; i++) { //寻找第一个峰
if(pos1[i]+pos2[i]>maxx) {
maxx=pos1[i]+pos2[i];
index=i;
}
}
pos[pos1[index]]=a[index];
stack<int> S;
for(int i=index-1; i>0; i--) { //利用单调栈寻找满足LIS的下标
if(a[i]>=pos[pos1[i]+1])
continue;
while(!S.empty()&&pos1[S.top()]<=pos1[i])
S.pop();
S.push(i);
pos[pos1[i]]=a[i];
}
vector<int> res;
while(!S.empty()) { //保存结果
int temp=S.top();
S.pop();
res.push_back(temp);
}
res.push_back(index);
for(int i=index+1; i<=n; i++) { //从第一个峰向后找递减的
int len=res.size();
if(pos2[i]==pos2[res[len-1]]-1 && a[i]<a[res[len-1]])
res.push_back(i);
}
return res;
}
vector<int> getLargeLEX(int n){
int index=1;
int maxx=pos1[1]+pos2[1];
for(int i=2; i<=n; i++) { //找最后一个峰
if(pos1[i]+pos2[i]>=maxx){
maxx=pos1[i]+pos2[i];
index=i;
}
}
memset(pos, INF, sizeof(pos));
stack<int> S;
S.push(index);
for(int i=index-1; i>0 ;i--) {//从前向后找递减的
if(pos1[i]==pos1[S.top()]-1 && a[i]<a[S.top()])
S.push(i);
}
vector<int> res;
while(!S.empty()){
int temp=S.top();
S.pop();
res.push_back(temp);
}
for(int i=index+1; i<=n ;i++){
if(a[i]>=pos[pos2[i]+1])
continue;
while(res.size()>=0 && pos2[i]>=pos2[res[res.size()-1]])
res.pop_back();
res.push_back(i);
pos[pos2[i]]=a[i];
}
return res;
}
int main(){
int n;
while (scanf("%d",&n)!=EOF) {
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
getLIS(n);
vector<int> small=getSmallLEX(n);
vector<int> large=getLargeLEX(n);
int len=small.size();
for(int i=0; i<len-1; i++)
printf("%d ",small[i]);
printf("%d\n",small[len-1]);
for(int i=0; i<len-1; i++)
printf("%d ",large[i]);
printf("%d\n",large[len-1]);
}
return 0;
}

浙公网安备 33010602011771号