链接:https://ac.nowcoder.com/acm/contest/11253/K 来源:牛客网
题目描述
ZYT had a magic permutation a1,a2,⋯ ,an and he constructed a sequence b1,b2,⋯bn by the following pseudo code:
Stk is an empty stack
for i = 1 to n :
while ( Stk is not empty ) and ( Stk's top > a[i] ) :
pop Stk
push a[i]
b[i]=Stk's size
But he somehow forgot the permutation a, and only got some k elements of bi.
Construct a permutation a satisfying these bi , or determine no such permutation exists.
Here a permutation refers to a sequence that contains all integers from 1 to n exactly once.
输入描述:
The first line contains two integers n,k(1≤k≤n) — the length of the permutation, the number of left bi.
Then k lines each contains two integer pi,xi denoting that bpi=xi.
输出描述:
Output one line with n integers a1,a2,⋯an — a possible permutation.
If no such permutation exists, output one integer -1.
示例1
输入
5 2
2 2
5 4
输出
1 2 5 3 4
其实这里的输出样例为1 2 3 5 4 也是可以的,1 2 3 5 4 的输出反而更好理解。
示例2
输入
10 1
1 10
输出
-1
备注:
It's guaranteed that n≤10^6,1≤pi,xi≤n, and ∀i≠j,pi≠pj.
思路:
题意是输出一个符合条件的a数组,保证a数组内元素按照要求依次入栈,第i步操作后栈内元素个数符合b数组对应b[i]的值。
按照伪代码的要求,当栈顶元素大于将要入栈的a[i]的值时,栈顶元素出栈,直到栈顶元素小于等于将要入栈的a[i]的值(注意这里是一个while循环,有可能会一直出栈,所以b数组内后面的元素值比前面的值小是有可能的)。当栈顶元素不大于将要入栈的a[i]的值时,a[i]入栈,更新b[i]为新的栈的大小。
其实也就是一个反推的过程,不理解的话可以手算一下。
但是如果写模拟的代码,可能会超时(当时写的时候确实是超时了,结束之后看别人的代码发现还是有人写模拟的,应该是写的方法问题,需要优化算法)。干脆直接对数组进行操作。
另外要注意,当出现pi的值小于xi的情况,例如pi=2,xi=5,正常情况应该是b2=2,想要在第二次操作b2时实现栈内有5个数,肯定是不可能实现的,当前最多只有2个数。这种情况就要输出-1。
代码:
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
int main() {
ios::sync_with_stdio(false);
int n,k;
cin>>n>>k;
vector<int> b(n+1);
while(k--){
int p,x;
cin>>p>>x;
b[p] = x;
}
int temp = 0;
for(int i=1;i<=n;i++){
temp++;
if(b[i] > 0){
if(b[i] > temp){ //当前位置与数字不匹配
cout << "-1\n";
return 0;
}
temp = b[i];
}else b[i] = temp; //根据所给数据填补b数组
}
vector<int> a(n+2);
for(int i=1;i<=n;i++){
a[b[i]]++; //记录需要变更的数
}
for(int i=2;i<=n+1;i++){
a[i] += a[i - 1]; //累加前一个的数
}
for(int i=1;i<=n;i++) {
cout << a[b[i]]-- <<" ";
}
cout<<'\n';
return 0;
}
另外还有类似模拟的代码,附在下面参考
#include <iostream>
#include <cstdio>
#include <stack>
#include <cstring>
using namespace std;
typedef long long ll;
const int N = 1e6+10;
int n,k;
int a[N],b[N],res[N];
stack<int>s;
stack<int>t;
int main()
{
scanf("%d%d",&n,&k);
memset(b,0,sizeof(b));
for(int i=0;i<k;i++){
int p,x;
scanf("%d%d",&p,&x);
b[p] = x;
}
int temp = 0,flag = 0;
while(!s.empty()) s.pop(); //清空栈
while(!t.empty()) t.pop(); //清空栈
for(int i=1;i<=n;i++){
temp++;
if(b[i] != 0){
if(temp < b[i]){ //当前位置与数字不匹配
flag = 1; //设置标记
break;
}
int cnt = temp - b[i];
for(int j=0;j<cnt;j++){
t.push(s.top());
s.pop();
}
temp = b[i];
}
s.push(i);
}
int tot = 1;
if(flag){
printf("-1\n");
return 0;
}
while(!s.empty()){
t.push(s.top());
s.pop();
}
while(!t.empty()){
res[t.top()] = tot++;
t.pop();
}
for(int i=1;i<=n;i++){
printf("%d",res[i]);
if(i != n) printf(" ");
else printf("\n");
}
return 0;
}