Graph constructive problems are back! This time the graph you are asked to build should match the following properties.

The graph is connected if and only if there exists a path between every pair of vertices.

The diameter (aka "longest shortest path") of a connected undirected graph is the maximum number of edges in the shortest path between any pair of its vertices.

The degree of a vertex is the number of edges incident to it.

Given a sequence of $n$ integers $a_1, a_2, \dots, a_n$ construct a connected undirected graph of $n$ vertices such that:  the graph contains no self-loops and no multiple edges;  the degree $d_i$ of the $i$-th vertex doesn't exceed $a_i$ (i.e. $d_i \le a_i$);  the diameter of the graph is maximum possible. 

Output the resulting graph or report that no solution exists.


-----Input-----

The first line contains a single integer $n$ ($3 \le n \le 500$) — the number of vertices in the graph.

The second line contains $n$ integers $a_1, a_2, \dots, a_n$ ($1 \le a_i \le n - 1$) — the upper limits to vertex degrees.


-----Output-----

Print "NO" if no graph can be constructed under the given conditions.

Otherwise print "YES" and the diameter of the resulting graph in the first line.

The second line should contain a single integer $m$ — the number of edges in the resulting graph.

The $i$-th of the next $m$ lines should contain two integers $v_i, u_i$ ($1 \le v_i, u_i \le n$, $v_i \neq u_i$) — the description of the $i$-th edge. The graph should contain no multiple edges — for each pair $(x, y)$ you output, you should output no more pairs $(x, y)$ or $(y, x)$.


-----Examples-----
Input
3
2 2 2

Output
YES 2
2
1 2
2 3

Input
5
1 4 1 1 1

Output
YES 2
4
1 2
3 2
4 2
5 2

Input
3
1 1 1

Output
NO



-----Note-----

Here are the graphs for the first two example cases. Both have diameter of $2$. [Image] $d_1 = 1 \le a_1 = 2$

$d_2 = 2 \le a_2 = 2$

$d_3 = 1 \le a_3 = 2$  [Image] $d_1 = 1 \le a_1 = 1$

$d_2 = 4 \le a_2 = 4$

$d_3 = 1 \le a_3 = 1$

$d_4 = 1 \le a_4 = 1$

Source: codeforces | Difficulty: MEDIUM_HARD
Tags: Graph algorithms

Implementation

Constructive algorithms


Solutions:
import sys, math, queue
MOD = 998244353
sys.setrecursionlimit(1000000)
n = int(input())
a = list(map(int, input().split()))
x = []
y = []
for i in range(n):
	if a[i] == 1:
		y.append(i + 1)
	else:
		x.append([a[i], i + 1])
if len(x) == 0 and n > 2:
	print('NO')
	exit()
e = []
for i in range(1, len(x)):
	e.append((x[i - 1][1], x[i][1]))
if len(x) >= 2:
	x[0][0] -= 1
	x[-1][0] -= 1
	for i in range(1, len(x) - 1):
		x[i][0] -= 2
d = len(e)
yp = 0
if x[0][0] > 0:
	if yp < len(y):
		e.append((x[0][1], y[yp]))
		x[0][0] -= 1
		yp += 1
		d += 1
	if len(x) == 1:
		if x[0][0] > 0:
			if yp < len(y):
				e.append((x[0][1], y[yp]))
				x[0][0] -= 1
				yp += 1
				d += 1
if len(x) > 1 and x[-1][0] > 0:
	if yp < len(y):
		e.append((x[-1][1], y[yp]))
		x[-1][0] -= 1
		yp += 1
		d += 1
for i in range(len(x)):
	while x[i][0] > 0 and yp < len(y):
		e.append((x[i][1], y[yp]))
		yp += 1
		x[i][0] -= 1
if yp < len(y):
	print('NO')
	exit()
print('YES', d)
print(n - 1)
for ei in e:
	print(*ei)


n = int(input())
a = list(map(int, input().split()))
if sum(a) < 2 * n - 2:
	print('NO')
else:
	one = []
	rst = []
	for i in range(0, n):
		if a[i] > 1:
			rst.append(i)
		else:
			one.append(i)
	ans = []
	for i in range(1, len(rst)):
		ans.append((rst[i], rst[i - 1]))
		a[rst[i]] -= 1
		a[rst[i - 1]] -= 1
	for i in range(1, len(one)):
		for j in range(0, len(rst)):
			if a[rst[j]] > 0:
				a[rst[j]] -= 1
				ans.append((rst[j], one[i]))
				break
	if len(one):
		for i in range(len(rst) - 1, -1, -1):
			if a[rst[i]] > 0:
				ans.append((rst[i], one[0]))
				break
	siz = min(len(one) + len(rst), 2 + len(rst)) - 1
	print('YES ', siz)
	print(len(ans))
	for (u, v) in ans:
		print(u + 1, v + 1)


import os
import sys
from math import *
from collections import *
from itertools import *
from heapq import *
from bisect import *
from io import BytesIO, IOBase

def vsInput():
	sys.stdin = open('input.txt', 'r')
	sys.stdout = open('output.txt', 'w')
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')
ALPHA = 'abcdefghijklmnopqrstuvwxyz'
M = 998244353
EPS = 1e-06

def Ceil(a, b):
	return a // b + int(a % b > 0)

def value():
	return tuple(map(int, input().split()))

def array():
	return [int(i) for i in input().split()]

def Int():
	return int(input())

def Str():
	return input()

def arrayS():
	return [i for i in input().split()]
for _ in range(1):
	n = Int()
	a = array()
	ones = [i for i in range(n) if a[i] == 1]
	ans = []
	nodes = []
	for i in range(n):
		if a[i] > 1:
			if len(nodes):
				ans.append((nodes[-1] + 1, i + 1))
				a[nodes[-1]] -= 1
				a[i] -= 1
			nodes.append(i)
	dia = len(ans)
	if nodes:
		if len(ones):
			x = ones.pop()
			ans.append((nodes[0] + 1, x + 1))
			a[nodes[0]] -= 1
			a[x] -= 1
			dia += 1
		if len(ones):
			x = ones.pop()
			ans.append((nodes[-1] + 1, x + 1))
			a[nodes[-1]] -= 1
			a[x] -= 1
			dia += 1
	for i in nodes:
		while a[i] > 0 and len(ones):
			x = ones.pop()
			ans.append((i + 1, x + 1))
			a[i] -= 1
			a[x] -= 1
	if len(ones):
		print('NO')
	else:
		print('YES', dia)
		print(len(ans))
		for i in ans:
			print(*i)


from collections import namedtuple
vertex = namedtuple('vertex', ['degree', 'id'])
(a, b, c) = ([], [], 0)
n = int(input())
rr = list(map(int, input().split()))
for i in range(n):
	if rr[i] > 1:
		a.append(vertex(rr[i], i + 1))
	else:
		b.append(vertex(rr[i], i + 1))
	c += rr[i]
if c < (n - 1) * 2:
	print('NO')
else:
	print('YES', len(a) - 1 + min(2, len(b)))
	print(n - 1)
	for i in range(1, len(a)):
		print(a[i - 1].id, a[i].id)
	if len(b) > 0:
		print(b[0].id, a[0].id)
	if len(b) > 1:
		print(b[1].id, a[-1].id)
	(j, yes) = (2, 0)
	for i in range(len(a)):
		k = a[i].degree - 2
		for t in range(k):
			if j >= len(b):
				yes = 1
				break
			print(a[i].id, b[j].id)
			j += 1
		if yes == 1:
			break


import os
import sys
from io import BytesIO, IOBase

def main():
	n = int(input())
	arr = list(map(int, input().split()))
	degree = sorted(range(n), key=lambda x: arr[x])
	if arr[degree[-1]] == 1:
		print('NO')
		exit()
	graph = []
	dm = 0
	z = n - 1
	flag = 0
	while z > 0:
		if arr[degree[z]] == 0:
			z -= 1
			flag = 1
			break
		graph.append((degree[z] + 1, degree[z - 1] + 1))
		dm += 1
		arr[degree[z]] -= 1
		arr[degree[z - 1]] -= 1
		z -= 1
	if flag:
		k = n - 1
		dm += 1
		while z >= 0 and arr[degree[k]]:
			while arr[degree[k]] and z >= 0:
				graph.append((degree[k] + 1, degree[z] + 1))
				arr[degree[z]] -= 1
				arr[degree[k]] -= 1
				z -= 1
			k -= 1
	else:
		z -= 1
	if z == -1:
		print('YES', dm)
		print(len(graph))
		for item in graph:
			print(*item)
	else:
		print('NO')
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')
main()


a = []
n = 0
Ones = []

def solution():
	s = 0
	for item in a:
		s = s + item
	if s < 2 * (n - 1):
		print('NO')
		return
	for i in range(n):
		if a[i] == 1:
			a[i] = 0
			Ones.append(i)
	t = len(Ones)
	d = n - t - 1 + min(2, t)
	print('YES ' + str(d) + '\n' + str(n - 1))
	l = -1
	if len(Ones) != 0:
		l = Ones[len(Ones) - 1]
		Ones.remove(l)
	for i in range(n):
		if a[i] > 1:
			if l != -1:
				a[l] = a[l] - 1
				a[i] = a[i] - 1
				print(str(l + 1) + ' ' + str(i + 1))
			l = i
	i = n - 1
	while i >= 0:
		while len(Ones) > 0 and a[i] > 0:
			a[i] = a[i] - 1
			u = Ones[len(Ones) - 1]
			print(str(i + 1) + ' ' + str(u + 1))
			Ones.remove(u)
		i = i - 1
line = int(input())
n = int(line)
line = str(input()).split()
for i in range(n):
	a.append(int(line[i]))
solution()


import sys
n = int(input())
A = list(map(int, input().split()))
if sum(A) < 2 * n - 2:
	print('NO')
	sys.exit()
ONES = A.count(1)
print('YES', min(n - 1, n - ONES + 1))
NOONE = []
for i in range(n):
	if A[i] != 1:
		NOONE.append([A[i], i + 1])
ANS = []
for i in range(1, len(NOONE)):
	ANS.append((NOONE[i - 1][1], NOONE[i][1]))
	NOONE[i - 1][0] -= 1
	NOONE[i][0] -= 1
NOONE = [[1, NOONE[-1][1]]] + NOONE[0:-1] + [[NOONE[-1][0] - 1, NOONE[-1][1]]]
LENNO = len(NOONE)
j = 0
for i in range(n):
	while j < LENNO and NOONE[j][0] == 0:
		j += 1
	if A[i] != 1:
		continue
	ANS.append((i + 1, NOONE[j][1]))
	NOONE[j][0] -= 1
print(len(ANS))
for (a, b) in ANS:
	print(a, b)


n = int(input())
deg = list(map(int, input().split()))
sumd = 0
deg_1 = []
deg_2 = []
for i in range(n):
	sumd += deg[i]
	if deg[i] > 1:
		deg_2.append(i)
	else:
		deg_1.append(i)
if sumd < 2 * n - 2:
	print('NO')
else:
	l1 = len(deg_1)
	l2 = len(deg_2)
	while l1 < 2:
		deg_1.append(deg_2[l2 - 1])
		l1 += 1
		l2 -= 1
	print('YES %d' % (n + 1 - l1))
	print(n - 1)
	for i in range(l2 - 1):
		print('%d %d' % (deg_2[i] + 1, deg_2[i + 1] + 1))
		deg[deg_2[i]] -= 1
		deg[deg_2[i + 1]] -= 1
	print('%d %d' % (deg_2[l2 - 1] + 1, deg_1[0] + 1))
	deg[deg_2[l2 - 1]] -= 1
	j = 0
	for i in range(1, l1):
		while deg[deg_2[j]] == 0:
			j += 1
		print('%d %d' % (deg_1[i] + 1, deg_2[j] + 1))
		deg[deg_2[j]] -= 1


n = int(input())
raw = map(int, input().split())
v = [[idx, deg] for (idx, deg) in zip(range(1, n + 1), raw)]
onedeg = list(filter(lambda x: x[1] == 1, v))
other = list(filter(lambda x: x[1] != 1, v))
(len1, len2) = (len(onedeg), len(other))
ansnum = len2 - 1 + (1 if len1 else 0) + (1 if len1 > 1 else 0)
s = []
for i in range(len2 - 1):
	s.append('%d %d' % (other[i][0], other[i + 1][0]))
	other[i][1] -= 1
	other[i + 1][1] -= 1

def build():
	global s, len1, len2, onedeg, other
	if len2 == 0:
		return False
	if len1:
		s.append('%d %d' % (onedeg[0][0], other[len2 - 1][0]))
		other[len2 - 1][1] -= 1
	j = 0
	for i in range(1, len1):
		while j < len2 and other[j][1] == 0:
			j += 1
		if j == len2:
			return False
		s.append('%d %d' % (onedeg[i][0], other[j][0]))
		other[j][1] -= 1
	return True
if build():
	print('YES %d\n%d' % (ansnum, len(s)))
	print('\n'.join(s))
else:
	print('NO')


n = int(input())
leafs = set()
other = {}
other_indices = []
s = 0
for (i, a) in enumerate(map(int, input().split())):
	if a == 1:
		leafs.add(i)
	else:
		other[i] = a
		other_indices.append(i)
	s += a
if not other:
	print('NO')
	exit(0)
other_indices.sort(key=lambda index: other[index])
other_indices = [other_indices[-1]] + other_indices[:-1]
edges = []
for (i1, i2) in zip(other_indices, other_indices[1:]):
	edges.append((i1, i2))
	other[i1] -= 1
	if other[i1] == 0:
		del other[i1]
	other[i2] -= 1
	if other[i2] == 0:
		del other[i2]
diam = len(other_indices) + min(2, len(leafs))
has_start = has_end = False
while leafs:
	if len(other) == 0:
		print('NO')
		exit(0)
	l = leafs.pop()
	if not has_start and other.get(other_indices[0], 0):
		i = other_indices[0]
		has_start = True
	elif not has_end and other.get(other_indices[-1], 0):
		i = other_indices[-1]
		has_end = True
	else:
		i = next(iter(other))
	edges.append((l, i))
	other[i] -= 1
	if other[i] == 0:
		del other[i]
print('YES', diam - 1)
print(len(edges))
for (x, y) in edges:
	print(x + 1, y + 1)


def bfs(a):
	booli = defaultdict(bool)
	booli[a] = True
	queue = [a]
	level = defaultdict(int)
	level[a] = 0
	maxi = 0
	yo = 0
	while queue:
		z = queue.pop(0)
		for i in hash[z]:
			if not booli[i]:
				booli[i] = True
				queue.append(i)
				level[i] = level[z] + 1
				if level[i] > maxi:
					maxi = level[i]
					yo = i
	return bfs1(yo)

def bfs1(a):
	booli = defaultdict(bool)
	booli[a] = True
	queue = [a]
	level = defaultdict(int)
	level[a] = 0
	maxi = 0
	while queue:
		z = queue.pop(0)
		for i in hash[z]:
			if not booli[i]:
				booli[i] = True
				queue.append(i)
				level[i] = level[z] + 1
				maxi = level[i]
	return maxi
import heapq
from collections import defaultdict
n = int(input())
l = list(map(int, input().split()))
l = [[i, j + 1] for (j, i) in enumerate(l)]
l.sort(reverse=True)
ans = []
(ha, cur) = l[0]
hash = defaultdict(list)
flag = 0
for i in range(1, n):
	if ha == 0:
		flag = 1
		break
	else:
		(a, b) = l[i]
		hash[cur].append(b)
		hash[b].append(cur)
		ha -= 1
		if ha != 0:
			ans.append([ha, cur])
		cur = b
		ha = a - 1
if flag == 1:
	l = l[i:]
	ans.sort(reverse=True)
	z = 0
	if ans == [] and l != []:
		print('NO')
		exit()
	i = 0
	n = len(l)
	while i < n:
		if ans == []:
			print('NO')
			exit()
		(a, b) = ans.pop(0)
		for j in range(a):
			hash[b].append(l[i][1])
			hash[l[i][1]].append(b)
			i += 1
			if i == n:
				break
		if ans == [] and i < n:
			print('NO')
			exit()
print('YES', bfs(1))
yo = set()
for i in hash:
	for j in hash[i]:
		yo.add(tuple(sorted((j, i))))
print(len(yo))
for (a, b) in yo:
	print(a, b)


def main():
	n = int(input())
	a = list(map(int, input().split()))
	if sum(a) < 2 * n - 2:
		print('NO')
		return
	Mx0 = 0
	for i in range(n):
		if a[i] < a[Mx0]:
			Mx0 = i
	Mx1 = 0 if Mx0 else 1
	for i in range(n):
		if i == Mx0:
			continue
		if a[i] < a[Mx1]:
			Mx1 = i
	ones = []
	non_ones = []
	for i in range(n):
		if i == Mx0 or i == Mx1:
			continue
		if a[i] == 1:
			ones.append(i)
		else:
			non_ones.append(i)
			a[i] -= 2
	print('YES', len(non_ones) + 2 - 1)
	print(n - 1)
	print(Mx0 + 1, non_ones[0] + 1)
	for i in range(len(non_ones) - 1):
		print(non_ones[i] + 1, non_ones[i + 1] + 1)
	print(non_ones[-1] + 1, Mx1 + 1)
	z = 0
	for i in range(len(ones)):
		while not a[non_ones[z]]:
			z += 1
		a[non_ones[z]] -= 1
		print(ones[i] + 1, non_ones[z] + 1)
main()


import sys
n = int(sys.stdin.readline().strip())
a = list(map(int, sys.stdin.readline().strip().split()))
if sum(a) < 2 * n - 2:
	print('NO')
else:
	nleaves = a.count(1)
	print('YES ' + str(n - max([nleaves, 2]) + 1))
	print(n - 1)
	leaves = []
	nonleaves = []
	multiplicity = [0]
	for i in range(0, n):
		if a[i] == 1:
			leaves.append(i)
		else:
			nonleaves.append(i)
			if len(multiplicity) < n:
				for j in range(0, a[i] - 2):
					multiplicity.append(i)
	if leaves != []:
		v = leaves.pop()
	else:
		v = nonleaves.pop()
	for w in nonleaves:
		print(str(v + 1) + ' ' + str(w + 1))
		v = w
	for w in leaves:
		print(str(v + 1) + ' ' + str(w + 1))
		v = multiplicity.pop()


import math
n = int(input())
a = list(map(int, input().split()))
one_deg = []
atleast_two = []
sorted_deg = []
for i in range(len(a)):
	if a[i] == 1:
		one_deg.append(i)
	else:
		atleast_two.append(i)
		sorted_deg.append([a[i] - 2, i])
if len(one_deg) >= 1:
	sorted_deg.append([0, one_deg[0]])
if len(one_deg) >= 2:
	sorted_deg.append([0, one_deg[1]])
sorted_deg.sort(reverse=True)
k = 0
edges = []
for i in range(len(atleast_two) - 1):
	edges.append([atleast_two[i], atleast_two[i + 1]])
if len(atleast_two):
	if len(one_deg) >= 1:
		edges.append([one_deg[0], atleast_two[0]])
		k += 1
	if len(one_deg) >= 2:
		edges.append([one_deg[1], atleast_two[-1]])
		k += 1
for [a, b] in sorted_deg:
	for j in range(a):
		if k < len(one_deg):
			edges.append([b, one_deg[k]])
			k += 1
	if k == len(one_deg):
		break
if k == len(one_deg):
	print('YES', len(sorted_deg) - 1)
	print(len(edges))
	for [a, b] in edges:
		print(a + 1, b + 1)
else:
	print('NO')


def out_edge(x, y):
	a[x] -= 1
	a[y] -= 1
	print(x, y)
n = int(input())
a = list(map(int, input().split()))
sa = sum(a)
ma = min(a)
if sa < 2 * (n - 1) or ma < 1:
	print('NO')
	exit()
verts = sorted(enumerate(a, 1), key=lambda x: x[1], reverse=True)
verts = [list(j) for j in verts]
outres = []
for kk in range(1, n):
	if verts[kk - 1][1] >= 1:
		outres.append((verts[kk][0], verts[kk - 1][0]))
		verts[kk][1] -= 1
		verts[kk - 1][1] -= 1
	else:
		break
else:
	kk += 1
path_len = kk
print('YES', min(n - 1, path_len))
reserve_start = 0
while kk < n:
	if verts[reserve_start][1] > 0:
		outres.append((verts[reserve_start][0], verts[kk][0]))
		verts[reserve_start][1] -= 1
		verts[kk][1] -= 1
		kk += 1
	else:
		reserve_start += 1
print(len(outres))
for oo in outres:
	print(*oo)


import math

def main():
	buf = input()
	n = int(buf)
	buf = input()
	buflist = buf.split()
	a = []
	for (i, item) in enumerate(buflist):
		a.append([i + 1, int(item)])
	a = list(reversed(list(sorted(a, key=lambda x: x[1]))))
	one_deg_count = 0
	for i in a:
		if i[1] == 1:
			one_deg_count += 1
	if one_deg_count == len(a):
		if one_deg_count == 2:
			print('YES', 1)
			print(1)
			print(1, 2)
		else:
			print('NO')
		return
	elif one_deg_count == len(a) - 1:
		if one_deg_count <= a[0][1]:
			print('YES', 2)
			print(one_deg_count)
			for i in range(one_deg_count):
				print(a[0][0], a[-i - 1][0])
		else:
			print('NO')
		return
	else:
		spare_edges = 2
		for i in range(len(a) - one_deg_count):
			spare_edges += a[i][1] - 2
		if spare_edges >= one_deg_count:
			diameter = len(a) - 1 - one_deg_count + min(one_deg_count, 2)
			edge_count = 0
			edge_list = []
			for i in range(len(a) - one_deg_count - 1):
				edge_list.append((a[i][0], a[i + 1][0]))
			for i in range(len(a) - one_deg_count):
				a[i][1] -= 2
			if one_deg_count > 0:
				edge_list.append((a[0][0], a[-1][0]))
				one_deg_count -= 1
			if one_deg_count > 0:
				edge_list.append((a[-one_deg_count - 2][0], a[-2][0]))
				one_deg_count -= 1
			idx = 0
			for i in range(one_deg_count):
				edge_list.append((a[idx][0], a[-i - 3][0]))
				a[idx][1] -= 1
				if a[idx][1] <= 0:
					idx += 1
			print('YES', diameter)
			print(len(edge_list))
			for i in edge_list:
				print(i[0], i[1])
		else:
			print('NO')
main()


n = int(input())
a = list(zip(list(map(int, input().split())), range(1, n + 1)))
ones = len(list(filter(lambda x: x[0] == 1, a)))
ones_list = list(filter(lambda x: x[0] == 1, a))
others = list(filter(lambda x: x[0] != 1, a))
others.sort()
used = []
ans = []
first = -1
last = -1
if len(others) >= 2 and ones_list:
	first = others[-1][1]
	others[-1] = (others[-1][0] - 1, others[-1][1])
	ans.append((first, ones_list.pop()[1]))
	ones -= 1
	if ones_list:
		last = others[-2][1]
		ans.append((last, ones_list.pop()[1]))
		ones -= 1
		others[-2] = (others[-2][0] - 1, others[-2][1])
		if not ones_list:
			others.pop()
			others.pop()
	else:
		others.pop()
	if ones_list:
		if others[-1][0] == 1:
			others.pop()
			if others[-1][0] == 1:
				others.pop()
		if len(others) >= 2 and others[-2][0] == 1:
			del others[-2]
while ones > 0 and others:
	if first == others[-1][1] or first == -1:
		x = others[-1][0] - 1
		if len(others) == 1:
			x += 1
		first = others[-1][1]
	elif last == others[-1][1]:
		x = others[-1][0] - 1
	else:
		x = others[-1][0] - 2
	if x > 0:
		if ones >= x:
			ones -= x
			while x > 0:
				ans.append((ones_list[-1][1], others[-1][1]))
				ones_list.pop()
				x -= 1
			if not (first == others[-1][1] or last == others[-1][1]):
				used.append(others[-1][1])
			others.pop()
		else:
			if not (first == others[-1][1] or last == others[-1][1]):
				used.append(others[-1][1])
			while ones > 0:
				ans.append((ones_list[-1][1], others[-1][1]))
				ones_list.pop()
				ones -= 1
			others.pop()
	else:
		break
if ones != 0:
	print('NO')
else:
	if first != -1 and last != -1:
		if used and others:
			d = len(used) + len(others) + 3
		elif used:
			d = len(used) + 3
		elif others:
			d = len(others) + 3
		else:
			d = 3
	elif first != -1:
		if others:
			d = len(others) + 1
		elif len(ans) == 1:
			d = 1
		else:
			d = 2
	else:
		d = len(others) - 1
	if used:
		ans.append((used[-1], first))
		while len(used) > 1:
			ans.append((used[-1], used[-2]))
			used.pop()
		if not others and last != -1:
			ans.append((used[-1], last))
	if others:
		if not used and first != -1:
			ans.append((others[-1][1], first))
		if used:
			ans.append((used[-1], others[-1][1]))
		while len(others) > 1:
			ans.append((others[-1][1], others[-2][1]))
			others.pop()
		if last != -1:
			ans.append((others[-1][1], last))
	if not others and (not used):
		if first != -1 and last != -1:
			ans.append((first, last))
	print('YES', d)
	print(len(ans))
	for x in ans:
		print(x[0], x[1])


from sys import stdin, stdout
import math
import heapq
from itertools import accumulate

def print_res(dia, ans):
	print('YES', dia)
	print(len(ans))
	for pair in ans:
		print(*pair)
N = int(input())
arr = [int(x) for x in stdin.readline().split()]
if N == 2:
	print('YES', 1)
	print(1)
	print('1 2')
	quit()
ans = []
visited = [0] * N
for i in range(N):
	if arr[i] > 1:
		ans.append(i)
		visited[i] = 1
if len(ans) == 0:
	print('NO')
	quit()
edge = []
for i in range(1, len(ans)):
	u = ans[i - 1]
	v = ans[i]
	edge.append([u + 1, v + 1])
	arr[u] -= 1
	arr[v] -= 1
diameter = len(ans) - 1
flag = 0
for i in range(N):
	if visited[i] == 0:
		flag = 1
		u = ans[0]
		arr[u] -= 1
		visited[i] = 1
		edge.append([i + 1, u + 1])
		break
if flag == 1:
	diameter += 1
else:
	print_res(diameter, edge)
	quit()
if arr[ans[-1]] == 0:
	do_nothing = 1
else:
	flag = 0
	u = ans[-1]
	for i in range(N):
		if visited[i] == 0:
			flag = 1
			arr[u] -= 1
			visited[i] = 1
			edge.append([i + 1, u + 1])
			break
	if flag == 1:
		diameter += 1
	else:
		print_res(diameter, edge)
		quit()
for i in range(N):
	if visited[i] == 0:
		flag = 0
		for j in range(len(ans)):
			u = ans[j]
			if arr[u] > 0:
				flag = 1
				arr[u] -= 1
				visited[i] = 1
				edge.append([i + 1, u + 1])
				break
		if flag == 0:
			print('NO')
			quit()
print_res(diameter, edge)


n = int(input())
l = list(map(int, input().split()))
(one, many) = ([], [])
(a, b, c) = (0, 0, 0)
for (i, d) in enumerate(l):
	if d == 1:
		one.append(i + 1)
		a += 1
	else:
		many.append((i + 1, d))
		b += 1
		c += d
if c - 2 * b + 2 < a:
	print('NO')
	exit()
print('YES', b + min(a, min(a, 2)) - 1)
print(n - 1)
left = []
dia = []
if one:
	dia.append(one.pop())
for (i, d) in many:
	dia.append(i)
	if d > 2:
		left.append((i, d - 2))
if one:
	dia.append(one.pop())
for i in range(len(dia) - 1):
	print(dia[i], dia[i + 1])
while one:
	(i, d) = left.pop()
	print(i, one.pop())
	if d > 1:
		left.append((i, d - 1))


import os, sys
from io import BytesIO, IOBase

def main():
	n = int(input())
	a = list(map(int, input().split()))
	(on, tw, fr) = ([], [], [])
	for i in range(n):
		if a[i] == 1:
			on.append(i + 1)
		else:
			tw.append(i + 1)
			fr.append(a[i])
	if not len(tw):
		print('NO')
		exit()
	edg = []
	for i in range(len(tw) - 1):
		edg.append((tw[i], tw[i + 1]))
		fr[i] -= 1
		fr[i + 1] -= 1
	j = 0
	if len(on):
		edg.append((tw[-1], on[0]))
		fr[-1] -= 1
	for i in on[1:]:
		while j != len(tw) and (not fr[j]):
			j += 1
		if j == len(tw):
			print('NO')
			break
		fr[j] -= 1
		edg.append((tw[j], i))
	else:
		print('YES', len(tw) - 1 + min(len(on), 2))
		print(len(edg))
		for i in edg:
			print(*i)
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')
main()


def ii():
	return int(input())

def mi():
	return map(int, input().split())

def li():
	return list(mi())
n = ii()
a = li()
lf = [(a[i], i) for i in range(n) if a[i] == 1]
it = [(a[i], i) for i in range(n) if a[i] > 1]
it.sort(reverse=True)
while len(lf) < 2:
	lf.append(it.pop())
ed = []
(_, last) = lf.pop()
for i in range(len(it)):
	(cap, u) = it[i]
	if i != 0:
		ed.append((it[i - 1][1], u))
		cap -= 1
	while lf and cap > 1:
		(_, l) = lf.pop()
		ed.append((u, l))
		cap -= 1
if lf:
	ans = 'NO'
else:
	ans = 'YES %d' % (len(it) + 1,)
	ed.append((it[-1][1], last))
	ans1 = str(len(ed))
	ans2 = '\n'.join(('%d %d' % (u + 1, v + 1) for (u, v) in ed))
	ans = '\n'.join([ans, ans1, ans2])
print(ans)


n = int(input())
a = [0]
sum = 0
for i in map(int, input().split()):
	a.append(i)
	sum += i
last = 0
ans = 0
edge = []
for i in range(1, n + 1, 1):
	if a[i] == 1:
		last = i
a[last] = 0
for i in range(1, n + 1, 1):
	if a[i] > 1:
		if last:
			edge.append([last, i])
			ans += 1
		last = i
for i in range(1, n + 1, 1):
	if a[i] == 1 and last:
		edge.append([last, i])
		last = 0
		a[i] = 0
		ans += 1
for i in range(1, n + 1, 1):
	for j in range(1, n + 1, 1):
		if a[j] == 1 and a[i] > 2:
			edge.append([i, j])
			a[i] -= 1
			a[j] -= 1
if len(edge) != n - 1:
	print('NO')
else:
	print('YES', ans)
	print(len(edge))
	for i in edge:
		print(i[0], i[1])


import sys
import math
from collections import defaultdict, deque
n = int(sys.stdin.readline())
deg = list(map(int, sys.stdin.readline().split()))
nodes = []
count = 0
leaf = 0
leaves = []
for i in range(n):
	if deg[i] > 1:
		nodes.append(i + 1)
		count += deg[i]
	else:
		leaf += 1
		leaves.append(i + 1)
if leaf > count - (len(nodes) - 1):
	print('NO')
	sys.exit()
graph = defaultdict(list)
(a, b) = (len(nodes), len(leaves))
dia = len(nodes)
for i in range(a - 1):
	graph[nodes[i]].append(nodes[i + 1])
	graph[nodes[i + 1]].append(nodes[i])
if len(leaves) == 1:
	graph[nodes[0]].append(leaves[0])
	graph[leaves[0]].append(nodes[0])
	dia += 1
elif len(leaves) >= 2:
	graph[nodes[0]].append(leaves[0])
	graph[nodes[-1]].append(leaves[1])
	graph[leaves[1]].append(nodes[-1])
	graph[leaves[0]].append(nodes[0])
	dia += 2
count = 2
i = 0
while count < b and i < a:
	while i < a and deg[nodes[i] - 1] > len(graph[nodes[i]]) and (count < b):
		graph[nodes[i]].append(leaves[count])
		graph[leaves[count]].append(nodes[i])
		count += 1
	i += 1
if i >= a and count < b:
	print('NO')
	sys.exit()
if b == 1:
	print('YES', dia - 1)
else:
	print('YES', dia - 1)
vis = defaultdict(int)
q = [1]
vis[1] = 1
print(n - 1)
while q:
	a = q.pop()
	for i in graph[a]:
		if vis[i] == 0:
			print(i, a)
			q.append(i)
			vis[i] = 1


n = int(input())
a = list(map(int, input().split()))
leaf = [i + 1 for i in range(n) if a[i] == 1]
root_w = [i + 1 for i in range(n) if a[i] != 1]
root_r = [a[i - 1] - 2 for i in root_w]
l_path = root_w
if len(leaf) != 0:
	l_path = [leaf[0]] + l_path
	leaf = leaf[1:]
if len(leaf) != 0:
	l_path = l_path + [leaf[0]]
	leaf = leaf[1:]
if sum(root_r) < len(leaf):
	print('NO')
else:
	print('YES {}'.format(len(l_path) - 1))
	print(n - 1)
	for i in range(len(l_path) - 1):
		print('{} {}'.format(l_path[i], l_path[i + 1]))
	for l in leaf:
		while len(root_r) > 0 and root_r[0] == 0:
			root_w = root_w[1:]
			root_r = root_r[1:]
		print('{} {}'.format(l, root_w[0]))
		root_r[0] = root_r[0] - 1


n = int(input())
A = [0] + list(map(int, input().split()))
vec = []
for i in range(1, n + 1):
	vec = vec + [[A[i], i]]
list.sort(vec)
list.reverse(vec)
if vec[0][0] == 1:
	print('NO')
	exit(0)
dia = 0
path = [vec[0][1]]
ans = []
(bol, col, idx) = (1, 1, 0)
for i in vec[1:]:
	if i[0] != 1:
		ans = ans + [[path[-1], i[1]]]
		dia = dia + 1
		A[path[-1]] = A[path[-1]] - 1
		path += [i[1]]
		A[path[-1]] = A[path[-1]] - 1
	elif col == 1:
		dia = dia + 1
		col = 0
		A[path[0]] -= 1
		ans = ans + [[path[0], i[1]]]
	elif bol == 1:
		dia = dia + 1
		bol = 0
		A[path[-1]] -= 1
		ans = ans + [[path[-1], i[1]]]
	else:
		while idx < len(path) and A[path[idx]] == 0:
			idx = idx + 1
		if idx == len(path):
			print('NO')
			exit(0)
		A[path[idx]] = A[path[idx]] - 1
		ans = ans + [[path[idx], i[1]]]
print('YES', dia)
print(len(ans))
for i in ans:
	print(i[0], i[1])


N = int(input())
D = [int(x) for x in input().split()]
if sum(D) < 2 * (N - 1):
	print('NO')
else:
	D = [0] + D
	gt2 = [i for i in range(1, N + 1) if D[i] > 1]
	gt1 = [i for i in range(1, N + 1) if D[i] == 1]
	ans = []
	if len(gt2) > 1:
		for i in range(len(gt2) - 1):
			ans.append((gt2[i], gt2[i + 1]))
		for i in range(1, len(gt2) - 1):
			D[gt2[i]] -= 2
		D[gt2[0]] -= 1
		D[gt2[-1]] -= 1
	diameter = len(gt2)
	if len(gt1) >= 2:
		ans.append((gt1[0], gt2[0]))
		ans.append((gt1[1], gt2[-1]))
		D[gt2[0]] -= 1
		D[gt2[-1]] -= 1
		diameter += 2
	elif len(gt1) >= 1:
		ans.append((gt1[0], gt2[0]))
		D[gt2[0]] -= 1
		diameter += 1
	else:
		pass
	t2i = 0
	for v in gt1[2:]:
		while t2i < len(gt2) and D[gt2[t2i]] <= 0:
			t2i += 1
		if t2i >= len(gt2):
			print('NO')
			exit(0)
		u = gt2[t2i]
		D[u] -= 1
		ans.append((v, u))
	print('YES {}'.format(diameter - 1))
	print(len(ans))
	print('\n'.join(['{} {}'.format(u, v) for (u, v) in ans]))


n = int(input())
a = list(map(int, input().split()))
b = []
c = []
e = []
for i in range(n):
	if a[i] == 1:
		b += [i]
for i in range(n):
	if a[i] != 1:
		c += [[a[i], i]]
if not c:
	print('NO')
	exit(0)
ans = len(c)
for i in range(len(c) - 1):
	e += [(c[i][1], c[i + 1][1])]
	c[i][0] -= 1
	c[i + 1][0] -= 1
if b:
	e += [(b[-1], c[-1][1])]
	c[-1][0] -= 1
	b.pop()
	ans += 1
if b:
	e += [(b[-1], c[0][1])]
	c[0][0] -= 1
	b.pop()
	ans += 1
i = 0
while b:
	while i < len(c) and c[i][0] == 0:
		i += 1
	if i == len(c):
		print('NO')
		exit(0)
	e += [(b[-1], c[i][1])]
	c[i][0] -= 1
	b.pop()
print('YES', ans - 1)
print(len(e))
for (x, y) in e:
	print(x + 1, y + 1)


n = int(input())
T = input().split(' ')
for i in range(n):
	T[i] = int(T[i])
L = []
M = []
t = 0
ip = 0
IP = []
for i in range(n):
	if T[i] >= 2:
		L.append(i + 1)
		M.append(T[i])
		t += T[i]
	else:
		ip += 1
		IP.append(i + 1)
if t - (2 * len(L) - 2) < ip:
	print('NO')
else:
	for i in range(1, len(L) - 1):
		M[i] -= 2
	if len(L) >= 2:
		M[0] -= 1
		M[-1] -= 1
	print('YES', end=' ')
	if ip == 0:
		print(len(L) - 1)
	elif ip == 1:
		print(len(L))
	else:
		print(len(L) + 1)
	print(len(L) - 1 + ip)
	if ip >= 1:
		print(IP[0], end=' ')
		print(L[0])
		M[0] -= 1
	if ip >= 2:
		print(IP[-1], end=' ')
		print(L[-1])
		M[-1] -= 1
	k = 1
	ind = 0
	while k < ip - 1:
		if M[ind] == 0:
			ind += 1
		else:
			print(IP[k], end=' ')
			print(L[ind])
			M[ind] -= 1
			k += 1
	for i in range(len(L) - 1):
		print(L[i], end=' ')
		print(L[i + 1])


n = int(input())
a = tuple(map(int, input().split()))
if n * 2 > sum(a) + 2:
	print('NO')
else:
	n1 = []
	on = []
	for i in range(n):
		if a[i] != 1:
			n1.append(i)
		else:
			on.append(i)
	print('YES', len(n1) + min(2, len(on)) - 1)
	print(n - 1)
	n1it = iter(n1)
	next(n1it)
	for (v, u) in zip(n1, n1it):
		print(v + 1, u + 1)
	if on:
		print(on.pop() + 1, n1[-1] + 1)
	if on:
		print(on.pop() + 1, n1[0] + 1)
	on = iter(on)
	for n11 in n1:
		for i in range(a[n11] - 2):
			try:
				print(n11 + 1, next(on) + 1)
			except StopIteration:
				break
		else:
			continue
		break


n = int(input())
ones = []
rest = []
for (i, x) in enumerate(input().split(), 1):
	x = int(x)
	if x == 1:
		ones += [(x, i)]
	else:
		rest += [(x, i)]
rest.sort()
rest.reverse()
result = len(rest) - 1
edges = set()
dec_ord = lambda x: (x[0] - 1, x[1])
for i in range(len(rest) - 1):
	rest[i] = dec_ord(rest[i])
	rest[i + 1] = dec_ord(rest[i + 1])
	edges.add((rest[i][1], rest[i + 1][1]))
if len(ones) > 0 and len(rest) > 0:
	(_, i) = ones.pop()
	rest[0] = dec_ord(rest[0])
	edges.add((rest[0][1], i))
	result += 1
if len(ones) > 0 and len(rest) > 0:
	(_, i) = ones.pop()
	rest[-1] = dec_ord(rest[-1])
	edges.add((rest[-1][1], i))
	result += 1
while len(ones) > 0 and len(rest) > 0:
	if rest[-1][0] == 0:
		rest.pop()
	else:
		rest[-1] = dec_ord(rest[-1])
		edges.add((rest[-1][1], ones[-1][1]))
		ones.pop()
if len(ones) > 0:
	print('NO')
else:
	print('YES', result)
	print(len(edges))
	for (x, y) in edges:
		print(x, y)


n = int(input())

def g(l, a):
	if a == 1:
		return 0
	if l in [0, a - 1]:
		return 1
	else:
		return 2
a = list(map(int, input().split()))
if sum(a) < 2 * n - 2:
	print('NO')
else:
	leaf = a.count(1)
	notl = []
	ls = []
	for i in range(n):
		if a[i] != 1:
			notl.append(i)
		else:
			ls.append(i)
	if len(ls) == 0:
		ls.append(notl.pop())
		ls.append(notl.pop())
	elif len(ls) == 1:
		ls.append(notl.pop())
	print('YES', len(notl) + 1)
	print(n - 1)
	for i in range(len(notl) - 1):
		print(notl[i] + 1, notl[i + 1] + 1)
	curr = 0
	curry = 0
	j = len(notl)
	for i in range(len(ls) - 1):
		while True:
			if curr == a[notl[curry]] - g(curry, j):
				curr = 0
				curry += 1
			else:
				break
		curr += 1
		print(ls[i] + 1, notl[curry] + 1)
	print(ls[-1] + 1, notl[-1] + 1)


import sys
n = int(input())
a = list(map(int, input().split()))
for i in range(n):
	a[i] = [i, a[i]]
a.sort(key=lambda x: x[1], reverse=True)
ans = []
index = 0
cnt = 0
tmp = 1
right_bool = False
left_bool = False
for i in range(1, n):
	if a[index][1] == 0:
		print('NO')
		sys.exit()
	if a[i][1] >= 2:
		ans.append([a[i - 1][0], a[i][0]])
		cnt += 1
		a[i - 1][1] -= 1
		a[i][1] -= 1
	elif right_bool == False:
		ans.append([a[i - 1][0], a[i][0]])
		a[i - 1][1] -= 1
		a[i][1] -= 1
		cnt += 1
		right_bool = True
	else:
		ans.append([a[index][0], a[i][0]])
		a[index][1] -= 1
		a[i][1] -= 1
		if left_bool == False:
			cnt += 1
			left_bool = True
		if a[index][1] == 0:
			index += 1
print('YES', cnt)
print(n - 1)
for i in range(n - 1):
	print(ans[i][0] + 1, ans[i][1] + 1)


def solve():
	n = int(input())
	max_degs = [int(x) for x in input().split()]
	B = [[i + 1, x] for (i, x) in enumerate(max_degs) if x >= 2]
	S = [[i + 1, x] for (i, x) in enumerate(max_degs) if x < 2]
	if 2 + sum((b - 2 for (_, b) in B)) < len(S):
		print('NO')
		return
	print('YES', len(B) + min(len(S), 2) - 1)
	print(n - 1)
	for k in range(len(B) - 1):
		(i, x) = B[k]
		(i_n, _) = B[k + 1]
		print(i, i_n)
		B[k][1] -= 1
		B[k + 1][1] -= 1
	k = 0
	for (i, (s_idx, _)) in enumerate(S):
		if i == 0:
			print(B[0][0], s_idx)
			B[0][1] -= 1
		elif i == 1:
			print(B[-1][0], s_idx)
			B[-1][1] -= 1
		else:
			while B[k][1] == 0:
				k += 1
			print(B[k][0], s_idx)
			B[k][1] -= 1
solve()


n = int(input())
a = [int(s) for s in input().split()]
os = 0
oss = []
nos = 0
nos_0 = -1
nos_1 = -1
sumnos = 0
for i in range(n):
	if a[i] == 1:
		os += 1
		oss.append(i + 1)
	else:
		sumnos += a[i]
		nos += 1
		if nos_0 == -1:
			nos_0 = i + 1
		nos_1 = i + 1
if os <= sumnos - 2 * (nos - 1):
	es = []
	oss_i = 0
	ans = nos - 1
	if os >= 1:
		ans += 1
		es.append((nos_0, oss[0]))
		oss_i += 1
	if os >= 2:
		ans += 1
		es.append((nos_1, oss[1]))
		oss_i += 1
	print('YES', ans)
	prev_nos = -1
	for i in range(n):
		if a[i] > 1:
			if prev_nos != -1:
				es.append((prev_nos + 1, i + 1))
			for j in range(a[i] - 2):
				if oss_i >= os:
					break
				es.append((i + 1, oss[oss_i]))
				oss_i += 1
			prev_nos = i
	print(len(es))
	for e in es:
		print(*e)
else:
	print('NO')


n = int(input())
a = list(map(int, input().split()))
m = [[a[i], i + 1] for i in range(n)]
graph = [[] for i in range(n)]
m.sort(reverse=True)
i = 0
if m[0][0] < 2:
	print('NO')
	exit()
m[0][0] -= 1
graph[0].append(m[1][1])
m[1][0] -= 1
j = 1
while True:
	try:
		if m[j][0] > 0:
			graph[j].append(m[j + 2][1])
			m[j][0] -= 1
			m[j + 2][0] -= 1
		else:
			break
	except:
		break
	j += 2
while True:
	try:
		if m[i][0] > 0:
			graph[i].append(m[i + 2][1])
			m[i][0] -= 1
			m[i + 2][0] -= 1
		else:
			break
	except:
		break
	i += 2
ma = 0
for l in range(n):
	ma += len(graph[l])
for k in range(i, n, 2):
	for q in range(0, min(i, j)):
		if m[q][0] != 0 and m[k][0] != 0 and (m[k][0] == a[m[k][1] - 1]):
			graph[q].append(m[k][1])
			m[k][0] -= 1
			m[q][0] -= 1
			break
for k in range(j, n, 2):
	for q in range(0, min(i, j)):
		if m[q][0] != 0 and m[k][0] != 0 and (m[k][0] == a[m[k][1] - 1]):
			graph[q].append(m[k][1])
			m[k][0] -= 1
			m[q][0] -= 1
			break
an = 0
for i in range(n):
	an += len(graph[i])
if an + 1 != n:
	print('NO')
	exit()
print('YES', ma)
print(an)
for i in range(n):
	for j in graph[i]:
		print(m[i][1], j)


n = int(input())
(o, t, m) = ([], [], [])
for (i, e) in enumerate(map(int, input().split())):
	if e == 1:
		o.append(i)
	else:
		m.append([e, i])
if len(m) == 0:
	print('NO')
	exit()
m.sort()
edges = []
res = len(m) - 1
for i in range(len(m) - 1):
	edges.append(f'{m[i][1] + 1} {m[i + 1][1] + 1}')
	m[i][0] -= 1
	m[i + 1][0] -= 1

def f(i):
	edges.append(f'{m[i][1] + 1} {o.pop() + 1}')
	m[i][0] -= 1
if len(o) >= 1:
	f(0)
	res += 1
if len(o) >= 1:
	f(-1)
	res += 1
if len(o) >= 1:
	i = 0
	while len(o) and i < len(m):
		if m[i][0] > 0:
			f(i)
		else:
			i += 1
if len(o) != 0:
	print('NO')
else:
	print('YES', res)
	print(len(edges))
	print('\n'.join(edges))


import sys
from array import array
import typing as Tp

def input():
	return sys.stdin.buffer.readline().decode('utf-8')

def main():
	n = int(input())
	deg = [0] + list(map(int, input().split()))
	(node, leaf) = ([], [])
	for i in range(1, n + 1):
		if deg[i] == 1:
			leaf.append(i)
		else:
			node.append(i)
	if len(node) == 0:
		print('NO')
		exit()
	if len(node) == 1:
		if len(leaf) > deg[node[0]]:
			print('NO')
		else:
			print(f'YES 2\n{n - 1}')
			for v in leaf:
				print(node[0], v)
		exit()
	dia = len(node) - 1 + min(2, len(leaf))
	edges = []
	if leaf:
		edges.append(f'{node[-1]} {leaf.pop()}')
	for (i, v) in enumerate(node):
		if i > 0:
			edges.append(f'{node[i - 1]} {v}')
			deg[v] -= 1
		while leaf and deg[v] > 1:
			edges.append(f'{v} {leaf.pop()}')
			deg[v] -= 1
	if leaf:
		print('NO')
	else:
		print(f'YES {dia}\n{len(edges)}')
		print('\n'.join(edges))
main()


from sys import stdin, stdout
import cProfile, math
from collections import Counter
from bisect import bisect_left, bisect, bisect_right
import itertools
from copy import deepcopy
from fractions import Fraction
import sys, threading
sys.setrecursionlimit(10 ** 6)
threading.stack_size(2 ** 27)
printHeap = str()
memory_constrained = False
P = 10 ** 9 + 7
import sys
sys.setrecursionlimit(10000000)

class Operation:

	def __init__(self, name, function, function_on_equal, neutral_value=0):
		self.name = name
		self.f = function
		self.f_on_equal = function_on_equal

def add_multiple(x, count):
	return x * count

def min_multiple(x, count):
	return x

def max_multiple(x, count):
	return x
sum_operation = Operation('sum', sum, add_multiple, 0)
min_operation = Operation('min', min, min_multiple, 1000000000.0)
max_operation = Operation('max', max, max_multiple, -1000000000.0)

class SegmentTree:

	def __init__(self, array, operations=[sum_operation, min_operation, max_operation]):
		self.array = array
		if type(operations) != list:
			raise TypeError('operations must be a list')
		self.operations = {}
		for op in operations:
			self.operations[op.name] = op
		self.root = SegmentTreeNode(0, len(array) - 1, self)

	def query(self, start, end, operation_name):
		if self.operations.get(operation_name) == None:
			raise Exception('This operation is not available')
		return self.root._query(start, end, self.operations[operation_name])

	def summary(self):
		return self.root.values

	def update(self, position, value):
		self.root._update(position, value)

	def update_range(self, start, end, value):
		self.root._update_range(start, end, value)

	def __repr__(self):
		return self.root.__repr__()

class SegmentTreeNode:

	def __init__(self, start, end, segment_tree):
		self.range = (start, end)
		self.parent_tree = segment_tree
		self.range_value = None
		self.values = {}
		self.left = None
		self.right = None
		if start == end:
			self._sync()
			return
		self.left = SegmentTreeNode(start, start + (end - start) // 2, segment_tree)
		self.right = SegmentTreeNode(start + (end - start) // 2 + 1, end, segment_tree)
		self._sync()

	def _query(self, start, end, operation):
		if end < self.range[0] or start > self.range[1]:
			return None
		if start <= self.range[0] and self.range[1] <= end:
			return self.values[operation.name]
		self._push()
		left_res = self.left._query(start, end, operation) if self.left else None
		right_res = self.right._query(start, end, operation) if self.right else None
		if left_res is None:
			return right_res
		if right_res is None:
			return left_res
		return operation.f([left_res, right_res])

	def _update(self, position, value):
		if position < self.range[0] or position > self.range[1]:
			return
		if position == self.range[0] and self.range[1] == position:
			self.parent_tree.array[position] = value
			self._sync()
			return
		self._push()
		self.left._update(position, value)
		self.right._update(position, value)
		self._sync()

	def _update_range(self, start, end, value):
		if end < self.range[0] or start > self.range[1]:
			return
		if start <= self.range[0] and self.range[1] <= end:
			self.range_value = value
			self._sync()
			return
		self._push()
		self.left._update_range(start, end, value)
		self.right._update_range(start, end, value)
		self._sync()

	def _sync(self):
		if self.range[0] == self.range[1]:
			for op in self.parent_tree.operations.values():
				current_value = self.parent_tree.array[self.range[0]]
				if self.range_value is not None:
					current_value = self.range_value
				self.values[op.name] = op.f([current_value])
		else:
			for op in self.parent_tree.operations.values():
				result = op.f([self.left.values[op.name], self.right.values[op.name]])
				if self.range_value is not None:
					bound_length = self.range[1] - self.range[0] + 1
					result = op.f_on_equal(self.range_value, bound_length)
				self.values[op.name] = result

	def _push(self):
		if self.range_value is None:
			return
		if self.left:
			self.left.range_value = self.range_value
			self.right.range_value = self.range_value
			self.left._sync()
			self.right._sync()
			self.range_value = None

	def __repr__(self):
		ans = '({}, {}): {}\n'.format(self.range[0], self.range[1], self.values)
		if self.left:
			ans += self.left.__repr__()
		if self.right:
			ans += self.right.__repr__()
		return ans

def display(string_to_print):
	stdout.write(str(string_to_print) + '\n')

def primeFactors(n):
	factors = dict()
	for i in range(2, math.ceil(math.sqrt(n)) + 1):
		while n % i == 0:
			if i in factors:
				factors[i] += 1
			else:
				factors[i] = 1
			n = n // i
	if n > 2:
		factors[n] = 1
	return factors

def isprime(n):
	if n < 4:
		return True
	if n % 2 == 0:
		return False
	if n % 3 == 0:
		return False
	i = 5
	w = 2
	while i * i <= n:
		if n % i == 0:
			return False
		i += w
		w = 6 - w
	return True

def test_print(*args):
	if testingMode:
		print(args)

def display_list(list1, sep=' '):
	stdout.write(sep.join(map(str, list1)) + '\n')

def get_int():
	return int(stdin.readline().strip())

def get_tuple():
	return map(int, stdin.readline().split())

def get_list():
	return list(map(int, stdin.readline().split()))
memory = dict()

def clear_cache():
	global memory
	memory = dict()

def cached_fn(fn, *args):
	global memory
	if args in memory:
		return memory[args]
	else:
		result = fn(*args)
		memory[args] = result
		return result
TestCases = False
testingMode = False
optimiseForReccursion = False

def comp(li):
	return len(li)

def main():
	n = get_int()
	li = get_list()
	extra = []
	res = []
	hooks_left = []
	used = []
	line_len = 0
	for (i, ele) in enumerate(li):
		if i == 0:
			hooks_left.append(li[i])
			used.append(i)
		elif ele == 1:
			extra.append(i)
		else:
			line_len += 1
			hooks_left[-1] -= 1
			hooks_left.append(li[i] - 1)
			res.append([used[-1] + 1, i + 1])
			used.append(i)
	if hooks_left[0] > 0 and len(extra) > 0:
		line_len += 1
		res.append([used[0] + 1, extra.pop() + 1])
		hooks_left[0] -= 1
	if hooks_left[-1] > 0 and len(extra) > 0:
		line_len += 1
		res.append([used[-1] + 1, extra.pop() + 1])
		hooks_left[-1] -= 1
	for (i, ele) in enumerate(hooks_left):
		if ele == 0:
			continue
		if len(extra) == 0:
			break
		while len(extra) > 0 and ele > 0:
			res.append([used[i] + 1, extra.pop() + 1])
			ele -= 1
	if len(extra) > 0:
		print('NO')
		return
	else:
		print('YES', line_len)
		print(len(res))
		for x in res:
			print(x[0], x[1])
		return
if TestCases:
	for _ in range(get_int()):
		cProfile.run('main()') if testingMode else main()
else:
	(cProfile.run('main()') if testingMode else main()) if not optimiseForReccursion else threading.Thread(target=main).start()


n = int(input())
a = list(map(int, input().split()))
deg_sum = sum(a)
if deg_sum // 2 < n - 1:
	print('NO')
	exit(0)
neighbors = {}
for i in range(n):
	neighbors[i] = []
path = []
for (i, max_deg) in enumerate(a):
	if max_deg > 1:
		path.append(i)
if len(path) < n:
	ones = list(filter(lambda x: x[1] == 1, enumerate(a)))
	path = [ones[0][0]] + path
	if len(path) < n:
		path.append(ones[1][0])

def add_edge(i, j):
	degs[i] += 1
	degs[j] += 1
	neighbors[i].append(j)
	neighbors[j].append(i)
degs = [0] * n
for (i, j) in zip(path, path[1:]):
	add_edge(i, j)
added = list(path)
remaining = list(set(range(n)) - set(path))
for rem in remaining:
	for i in added:
		if degs[i] < a[i]:
			add_edge(i, rem)
			added.append(rem)
			break
	else:
		print('NO')
		exit(0)
print('YES {}'.format(len(path) - 1))
print(sum(degs) // 2)
for i in neighbors:
	for j in neighbors[i]:
		if i < j:
			print('{} {}'.format(i + 1, j + 1))


n = int(input())
l = [int(c) for c in input().split()]
ll = []
res = []
head = 0
dia = 0
for i in range(1, n):
	if l[i] == 1:
		l[i] = 0
		ll.append(i)
	else:
		res.append((head + 1, i + 1))
		l[head] -= 1
		dia += 1
		head = i
		l[head] -= 1
if l[head] > 0 and len(ll) > 0:
	res.append((ll[0] + 1, head + 1))
	l[head] -= 1
	del ll[0]
	dia += 1
if l[0] > 0 and len(ll) > 0:
	res.append((ll[0] + 1, 1))
	l[0] -= 1
	del ll[0]
	dia += 1
for i in ll:
	for j in range(n):
		if l[j] > 0:
			res.append((j + 1, i + 1))
			l[j] -= 1
			break
if len(res) < n - 1:
	print('NO')
else:
	print('YES ' + str(dia))
	print(n - 1)
	for p in res:
		print(p[0], end=' ')
		print(p[1])


def solve():
	N = int(input())
	A = [int(k) for k in input().split()]
	sumA = sum(A)
	if sumA < 2 * N - 2:
		print('NO')
		return
	ones = []
	for i in range(N):
		if A[i] == 1:
			A[i] = 0
			ones.append(i)
	t = len(ones)
	dm = N - t - 1 + min(2, t)
	results = []
	results.append('YES ' + str(dm))
	results.append(str(N - 1))
	lst = -1
	if t > 0:
		lst = ones[-1]
		ones.pop()
	for i in range(N):
		if A[i] > 1:
			if lst != -1:
				A[lst] -= 1
				A[i] -= 1
				results.append(str(lst + 1) + ' ' + str(i + 1))
			lst = i
	for i in range(N - 1, -1, -1):
		while ones and A[i] > 0:
			A[i] -= 1
			results.append(str(i + 1) + ' ' + str(ones[-1] + 1))
			ones.pop()
	print('\n'.join((k for k in results)))

def __starting_point():
	solve()
__starting_point()


n = int(input())
a = list(map(int, input().split()))
l = []
for i in range(n):
	l.append([a[i], i])
l.sort(key=lambda x: x[0])
for i in range(n):
	if l[i][0] > 1:
		break
j = 0
for k in range(i, n):
	j += l[k][0] - 2
if j < i - 2:
	print('NO')
else:
	print('YES', n - i + min(2, i) - 1)
	print(n - 1)
	k = 2
	for j in range(i, n - 1):
		print(l[j][1] + 1, l[j + 1][1] + 1)
	if i > 0:
		print(l[0][1] + 1, l[i][1] + 1)
	if i > 1:
		print(l[1][1] + 1, l[n - 1][1] + 1)
	if i > 2:
		for j in range(i, n):
			if k == i:
				break
			for p in range(2, l[j][0]):
				print(l[k][1] + 1, l[j][1] + 1)
				k += 1
				if k == i:
					break


n = int(input())
singles = []
branches = []
freeslots = []
for (i, degree) in enumerate(input().split()):
	if int(degree) == 1:
		singles.append(i)
	else:
		branches.append(i)
		freeslots.extend([i] * (int(degree) - 2))
if len(singles) > len(freeslots) + 2:
	print('NO')
else:
	print('YES {}'.format(len(branches) + min(len(singles), 2) - 1))
	print(n - 1)
	if branches:
		for i in range(len(branches) - 1):
			print('{} {}'.format(branches[i] + 1, branches[i + 1] + 1))
		if singles:
			print('{} {}'.format(singles.pop(0) + 1, branches[0] + 1))
		if singles:
			print('{} {}'.format(singles.pop(0) + 1, branches[-1] + 1))
		for single in singles:
			print('{} {}'.format(single + 1, freeslots.pop() + 1))
	elif len(singles) == 2:
		print('{} {}'.format(singles[0] + 1, singles[1] + 1))