【XSY2271】青蛙(栈)

题面

Description

从前有 nnn 块石头排成一排,编号从111到nnn。有 nnn 只青蛙站在这 nnn 块石头上,其中编号为 iii 的青蛙站在编号 iii 的石头上。

nnn 只青蛙有一个秘密计划,在某个风和日丽的早上,它们同时起跳,编号为 iii 的青蛙跳到编号为 pip_ipi​ 的石头上。跳跃之后,每个石头上仍然有且仅有一只青蛙。即: pip_ipi​ 为一个 111 到 nnn 的全排列。

天上有颗卫星,可以监控青蛙的跳动。由于一些技术原因,卫星只能提供有限的信息:对于 (i,i+1)(i,i+1)(i,i+1) 区间(其中 1i&lt;n1≤i&lt;n1≤i<n),有多少只青蛙经过此区间。例如:一只青蛙从编号为444的石头跳到编号为111的石头,它将依次经过 (3,4)(3,4)(3,4), (2,3)(2,3)(2,3), (1,2)(1,2)(1,2) 共三个区间。

我们想根据卫星提供的信息还原出每只青蛙跳到哪块石头上(即 pip_ipi​ )。

Input

第一行一个整数 nnn ,表示青蛙数量 (2n2×105)(2≤n≤2×10^5)(2≤n≤2×105)

第二行包含 n1n−1n−1 个整数 a1,a2,an1(0ai2×105)a_1,a_2,⋯a_{n−1}(0≤a_i≤2×10^5)a1​,a2​,⋯an−1​(0≤ai​≤2×105) ,其中 aia_iai​ 表示有多少只青蛙经过 (i,i+1)(i,i+1)(i,i+1) 区间。

Output

如果不存在跳跃方案,输出No

否则在第一行输出Yes,第二行输出 nnn 个整数 p1,p2,,pnp_1,p_2,⋯,p_np1​,p2​,⋯,pn​ 。如果有多组解,输出任意一种。

Sample Input & Sample Output

【样例输入1】

5
2 4 2 2

【样例输出1】

Yes
4 3 2 5 1

【样例输入2】

4
1 2 3

【样例输出2】

No

HINT

【数据范围与约定】

子任务1(101010分): 1n101≤n≤101≤n≤10

子任务2(404040分): 1n20001≤n≤20001≤n≤2000

子任务3(505050分): 1n2×1051≤n≤2×10^51≤n≤2×105

题解

首先注意到一个性质:每一个a[i]a[i]a[i]都得是偶数(如果左边跳一只青蛙到右边,则右边必定有一只青蛙跳到左边,这样会使a[i]a[i]a[i]加两次)。

然后,我们考虑相邻的两个aaa:a[i1]a[i-1]a[i−1]与a[i]a[i]a[i]。

它们只能有这三种关系:

  1. a[i1]=a[i]a[i-1]=a[i]a[i−1]=a[i]

  2. a[i1]+2=a[i]a[i-1]+2=a[i]a[i−1]+2=a[i]

  3. a[i1]2=a[i]a[i-1]-2=a[i]a[i−1]−2=a[i]

来逐一解释一下:

  1. a[i1]=a[i]a[i-1]=a[i]a[i−1]=a[i]

    这说明青蛙越过这两个区间的合法情况是这样的:

    (其中的红线代表青蛙跳跃的路线)

    【XSY2271】青蛙(栈)

    即如果有青蛙经过区间(i1,i)(i-1,i)(i−1,i),它必定要经过(i,i+1)(i,i+1)(i,i+1),否则a[i1]a[i]a[i-1]\neq a[i]a[i−1]̸​=a[i]。而由于题目要求输出任意一种方案,我们不妨令青蛙iii跳到了原地。

  2. a[i1]+2=a[i]a[i-1]+2=a[i]a[i−1]+2=a[i]

    还是画个图先:

    【XSY2271】青蛙(栈)

    意思就是,该经过的还是两个都得经过,不过iii要往右跳,另一个人要从右边跳到iii,这样才能使得a[i]=a[i1]+2a[i]=a[i-1]+2a[i]=a[i−1]+2。而由于题目要求输出任意一种方案,我们不妨设iii与右边的某只青蛙互换了位置。然后我们将iii插入一个栈里面。

  3. a[i1]2=a[i]a[i-1]-2=a[i]a[i−1]−2=a[i]

    图:

    【XSY2271】青蛙(栈)

    意思就是,该经过的还是两个都得经过,不过iii要往左跳,另一个人要从左边跳到iii,这样才能使得a[i]=a[i1]2a[i]=a[i-1]-2a[i]=a[i−1]−2。而由于题目要求输出任意一种方案,我们不妨设iii与左边的某只青蛙互换了位置。所以我们取栈顶的元素,这个元素xxx代表着xxx要与xxx右边的某个元素交换位置,而由于我们是从小到大循环遍历iii的,所以第iii只青蛙刚好符合条件。所以xxx与iii互换位置(p[i]=x,p[x]=ip[i]=x,p[x]=ip[i]=x,p[x]=i)。

最后把p[i]p[i]p[i]输出了就好了。

代码如下:

#include<bits/stdc++.h>

#define N 200010

using namespace std;

int n,a[N],p[N],st[N],top;

void NO()
{
	puts("No");
	exit(0);
}

int main()
{
	scanf("%d",&n);
	for(int i=1;i<n;i++)
		scanf("%d",&a[i]);
	for(int i=1;i<=n;i++)
	{
		if(a[i]==a[i-1])//自己跳自己
			p[i]=i;
		else if(a[i]==a[i-1]+2)//i往右跳 
			st[++top]=i;
		else if(a[i]==a[i-1]-2)//i往左跳
		{
			if(!top)//i往左跳,如果左边没人跳过来,就说明i跳不过去 
				NO();
			p[st[top]]=i;
			p[i]=st[top--];
		}
		else
			NO();//因为每一个a[i]得是偶数且与相邻两个的相差不超过2,其他情况不符合 
	}
	if(top)//栈里还有青蛙要往右跳,说明不合法 
		NO();
	puts("Yes");
	for(int i=1;i<=n;i++)
		printf("%d ",p[i]);
	return 0;
}
上一篇:Codeforces Round #501 (Div. 3)


下一篇:HDU5952 dfs+剪枝