问题 F: Escape Room
时间限制: 1 Sec 内存限制: 128 MB提交: 63 解决: 27
[提交][状态][讨论版][命题人:admin]
题目描述
As you know, escape rooms became very popular since they allow you to play the role of a video game hero. One such room has the following quiz. You know that the locker password is a permutation of N numbers. A permutation of length N is a sequence of distinct positive integers, whose values are at most N. You got the following hint regarding the password - the length of the longest increasing subsequence starting at position i equals Ai. Therefore you want to find the password using these values. As there can be several possible permutations you want to find the lexicographically smallest one. Permutation P is lexicographically smaller than permutation Q if there is an index i such that Pi < Qi and Pj = Qj for all j < i. It is guaranteed that there is at least one possible permutation satisfying the above constraints.
Can you open the door?
Can you open the door?
输入
The first line of the input contains one integer N (1≤N≤105).
The next line contains N space-separated integer Ai (1≤Ai≤N).
It’s guaranteed that at least one possible permutation exists.
The next line contains N space-separated integer Ai (1≤Ai≤N).
It’s guaranteed that at least one possible permutation exists.
输出
Print in one line the lexicographically smallest permutation that satisfies all the conditions.
样例输入
4
1 2 2 1
样例输出4 2 1 3
**************************************************************************
是一道关于最长上升子序列的思维题吧 就归到了dp里
题意:
给你n个数 是每个数从该位置到末位的最长上升子序列的最大长度
求一个符合的数列(如果多个输出最小)
//
例如样例输出 :4 2 1 3
(4的最长上升长度为1;2的最长上升长度为2;1的最长上升长度为2;3的最长上升长度为1)
即为样例输入:1 2 2 1
一开始的想法就是 1 2 2 1每次遍历最小的将4 3 2 1 顺序填入
但是每次都要遍历,我就试着同时遍历最大和最小,但还是tle了
我的tle错误代码:
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; int main() { int n; int a[100005]={0}; int ans[100005]={0}; scanf("%d",&n); int maxx = 0; for(int i=0;i<n;i++) { scanf("%d",&a[i]); if(a[i]>maxx) maxx = a[i]; } int p=1,q=maxx; //min max order int cnt1=1,cnt2=n; // min max num while(1) { if(p>q) break; for(int i=0;i<n;i++) { if(a[i]==p) { ans[i]=cnt2; cnt2--; } if(a[n-1-i]==q) { ans[n-1-i]=cnt1; cnt1++; } } // for(int i=0;i<n;i++) // { // printf("%d ",ans[i]); // } //printf(" "); p++; q--; } for(int i=0;i<n-1;i++) { printf("%d ",ans[i]); } printf("%d",ans[n-1]); }
然后队友想了一种算法:用三维的结构体
为了更容易明白 我写了组样例:1 1 2 3 3 2 1 1
第一步:将第一维的最大上升序列的下标记在第二维(用于记录原来的位置):
第一维x: 1 1 2 3 3 2 1 1
第二维num:1 2 3 4 5 6 7 8
按第一维排序:
x: 1 1 1 1 2 2 3 3
num:1 2 7 8 3 6 4 5
第三维:8 7 6 5 4 3 2 1(倒序填入对应的x)
为了将x变回原本的位置
将整个结构体按num再次排序
返回原本的顺序
x: 1 1 2 3 3 2 1 1
num:1 2 3 4 5 6 7 8
r: 8 7 4 2 1 3 6 5
输出的第三维就是答案
正确代码:
#include <sstream> #include <iostream> #include <string> #include<stdlib.h> #include<stdio.h> #include<algorithm> using namespace std; struct po //结构体 { int x,num,r; }; bool cmp1(po a,po b) { if(a.x!=b.x) return a.x<b.x; return a.num<b.num; } bool cmp2(po a,po b) { return a.num<b.num; } int main() { struct po s[100008]= {0}; int n,i,x,t; scanf("%d",&n); for(i=1; i<=n; i++) { scanf("%d",&t); s[i].num=i; //将原本顺序填入num中 s[i].x=t; } sort(s+1,s+1+n,cmp1); //按x排 int k=n; for(i=1; i<=n; i++) //倒序填入 { s[i].r=k; k--; } sort(s+1,s+1+n,cmp2); //按num排序 使结构体恢复原本顺序 for(i=1;i<n;i++)printf("%d ",s[i].r); //输出 r printf("%d ",s[n].r); return 0; }