#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void solved() {
int n; // 节点数量
cin >> n; // 读取节点数量
vector<int> d(n + 1); // 存储每个节点的度数,数组大小为 n+1,方便从1开始索引
int sum = 0; // 用于存储所有节点度数的总和
for (int i = 1; i <= n; i++) { // 读取每个节点的度数
cin >> d[i]; // 输入第i个节点的度数
sum += d[i]; // 累加度数总和
}
if (sum & 1) { // 特判:如果度数总和是奇数,无法构造二分图
cout << -1; // 输出-1表示无解
return; // 退出函数
}
// 动态规划部分,使用01背包思想
// 定义状态f[i][j]:前i个节点中,选择一些节点,使得它们的度数和恰好为j的最多个数
// ff数组用来跟踪解,ff[i][j]:当前的f[i][j]是否选了第i个数(0表示没选,1表示选了)
vector<vector<int>> f(n + 1, vector<int>(sum / 2 + 1, -1e9)); // 初始化f数组,初始值为一个很大的负数
vector<vector<int>> ff(n + 1, vector<int>(sum / 2 + 1, 0)); // 初始化ff数组,初始值为0
for (int i = 0; i <= n; i++) f[i][0] = 0; // 当度数和为0时,选择数量为0
for (int i = 1; i <= n; i++) { // 遍历每个节点
for (int j = 1; j <= sum / 2; j++) { // 遍历每个可能的度数和
if (j >= d[i] && f[i - 1][j] <= f[i - 1][j - d[i]] + 1) { // 如果当前节点可以加入集合,并且选择它更优
f[i][j] = f[i - 1][j - d[i]] + 1; // 更新f数组,选择当前节点
ff[i][j] = 1; // 标记选择状态为1,表示选择了当前节点
} else {
f[i][j] = f[i - 1][j]; // 不选择当前节点,继承上一个状态
}
}
}
int cnt = 0; // 用于存储边的数量
vector<int> l, r; // 用于存储两个集合的节点
if (f[n][sum / 2] <= 0) { // 如果无法找到一种组合使得度数和为sum/2
cout << -1; // 输出-1表示无解
return; // 退出函数
} else { // 如果有解
int now = sum / 2; // 当前目标度数和
for (int i = n; i >= 1; i--) { // 跟踪解
if (ff[i][now]) { // 如果选择了当前节点
l.push_back(i); // 将当前节点加入集合l
now -= d[i]; // 更新当前目标度数和
cnt += d[i]; // 累加边的数量
} else {
r.push_back(i); // 否则将当前节点加入集合r
}
}
}
cout << cnt << '\n'; // 输出边的数量
for (int lx : l) { // 遍历集合l中的每个节点
for (int rx : r) { // 遍历集合r中的每个节点
int z = min(d[lx], d[rx]); // 计算两个节点之间可以连接的边数
d[lx] -= z; // 更新集合l中节点的剩余度数
d[rx] -= z; // 更新集合r中节点的剩余度数
while (z--) cout << lx << ' ' << rx << '\n'; // 输出每条边
}
}
}
int main() {
solved(); // 调用solved函数
return 0;
}