Problem:
Score : 700 points

Problem Statement

There are N towns numbered 1, 2, \cdots, N.

Some roads are planned to be built so that each of them connects two distinct towns bidirectionally. Currently, there are no roads connecting towns.

In the planning of construction, each town chooses one town different from itself and requests the following: roads are built so that the chosen town is reachable from itself using one or more roads.

These requests from the towns are represented by an array P_1, P_2, \cdots, P_N. If P_i = -1, it means that Town i has not chosen the request; if 1 \leq P_i \leq N, it means that Town i has chosen Town P_i.

Let K be the number of towns i such that P_i = -1. There are (N-1)^K ways in which the towns can make the requests. For each way to make requests, find the minimum number of roads needed to meet all the requests, and print the sum of those (N-1)^K numbers, modulo (10^9+7).

Constraints

2 \leq N \leq 5000

P_i = -1 or 1 \leq P_i \leq N.

P_i \neq i

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N
P_1 P_2 \cdots P_N

Output

For each way to make requests, find the minimum number of roads needed to meet all the requests, and print the sum of those (N-1)^K numbers, modulo (10^9+7).

Sample Input 1

4
2 1 -1 3

Sample Output 1

8

There are three ways to make requests, as follows:

Choose P_1 = 2, P_2 = 1, P_3 = 1, P_4 = 3. In this case, at least three roads - for example, (1,2),(1,3),(3,4) - are needed to meet the requests.

Choose P_1 = 2, P_2 = 1, P_3 = 2, P_4 = 3. In this case, at least three roads - for example, (1,2),(1,3),(3,4) - are needed to meet the requests.

Choose P_1 = 2, P_2 = 1, P_3 = 4, P_4 = 3. In this case, at least two roads - for example, (1,2),(3,4) - are needed to meet the requests.

Note that it is not mandatory to connect Town i and Town P_i directly.

The sum of the above numbers is 8.

Sample Input 2

2
2 1

Sample Output 2

1

There may be just one fixed way to make requests.

Sample Input 3

10
2 6 9 -1 6 9 -1 -1 -1 -1

Sample Output 3

527841

Solution in C# (.NET Core 3.1.201) (judge verdict: Accepted)

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Text;
using System.Linq;

using E = System.Linq.Enumerable;

internal partial class Solver {
    public void Run() {
        var n = ni();
        var p = ni(n);
        var mod = ModInt.SetModValue(1000000000 + 7);
        var unknownNum = 0;
        for (int i = 0; i < n; i++) {
            if (p[i] != -1) {
                p[i]--;
            } else {
                unknownNum++;
            }
        }
        var D = new DisjointSet(n);
        long added = 0;
        for (int i = 0; i < n; i++) {
            if (p[i] == -1) continue;
            if (D.Unite(i, p[i])) {
                added++;
            }
        }
        ModInt ans = 0;

        ans += added * ModInt.Pow(n - 1, unknownNum);

        var group = E.Range(0, n)
            .GroupBy(i => D.Root(i))
            .Select((g, index) => new { Index = index, Count = g.LongCount(), HasUnknown = g.Any(i => p[i] == -1) })
            .ToArray();

        //group.Dump();

        var patterns = ModInt.Powers(n - 1, unknownNum + 10);

        foreach (var g in group) {
            if (!g.HasUnknown) continue;
            ModInt sub = 0;
            foreach (var g2 in group) {
                if (g.Index == g2.Index) continue;
                sub += patterns[unknownNum - 1] * g2.Count;
            }
            ans += sub;
        }

        var u = group.Where(g => g.HasUnknown)
            .Select(g => g.Count)
            .ToArray();

        //u.Dump();

        var memo = new ModInt?[5002, 5002];

        ModInt dfs(int pos, int k) {
            if (pos == u.Length) {
                return (k == 0) ? 1 : 0;
            } else {
                var rem = u.Length - pos;
                if (k - rem > 0) return 0;
                if (k == 0) return 1;
                ref var ret = ref memo[pos, k];
                if (!ret.HasValue) {
                    ModInt val = 0;
                    val += dfs(pos + 1, k);
                    val += dfs(pos + 1, k - 1) * u[pos];
                    ret = val;
                }
                return ret.Value;

            }
        }

        var fact = ModInt.Factorials(5002);

        for (int i = 2; i <= u.Length; i++) {
            var value = dfs(0, i);
            ans -= fact[i - 1] * value * patterns[unknownNum - i];
        }

        cout.WriteLine(ans);
    }
}

public class DisjointSet {
    private readonly long[] group;
    public int GroupCount { get; private set; }
    public DisjointSet(int n, int[] size = null) {
        group = new long[n];
        Clear(size);
        GroupCount = n;
    }
    public bool Unite(int x, int y) {
        x = Root(x); y = Root(y);
        if (x == y) {
            return false;
        }

        if (group[y] < group[x]) {
            return Unite(y, x);
        }

        group[x] += group[y];
        group[y] = x;
        GroupCount--;
        return true;
    }
    public bool IsSameSet(int x, int y) { return Root(x) == Root(y); }
    public int Root(int x) { return group[x] < 0 ? x : (int)(group[x] = Root((int)group[x])); }
    public long Size(int x) { return -group[Root(x)]; }
    public void Clear(int[] size = null) {
        for (int i = 0; i < group.Length; i++) {
            group[i] = -(size == null ? 1 : size[i]);
        }
    }
};
public partial struct ModInt {
    public static ModInt[] Factorials(int size) {
        var ret = new ModInt[size + 1];
        ret[0] = 1;
        for (int i = 1; i < ret.Length; i++) {
            ret[i] = ret[i - 1] * i;
        }
        return ret;
    }
    public static ModInt[] Powers(ModInt x, int size) {
        var ret = new ModInt[size + 1];
        ret[0] = 1;
        for (int i = 1; i < ret.Length; i++) {
            ret[i] = ret[i - 1] * x;
        }
        return ret;
    }
}

public partial struct ModInt : IEquatable<ModInt> {
    private static int mod = 0;
    private long _value;

    public ModInt(long x) {
        _value = x;
        Normalize();
    }

    private static long RegularMod(long x, int mod) {
        if (x >= mod) {
            if (x < 2 * mod) {
                return x - mod;
            }

            return x % mod;
        }
        if (x >= 0) {
            return x;
        }

        x = mod - RegularMod(-x, mod);
        if (x == mod) {
            return 0;
        }

        return x;
    }

    public static int SetModValue(int m) {
        return mod = m;
    }

    private void Normalize() {
        _value = RegularMod(_value, mod);
    }

    public override string ToString() {
        return _value.ToString(CultureInfo.InvariantCulture);
    }

    public int ToInt() {
        return (int)_value;
    }

    public static bool operator ==(ModInt c1, ModInt c2) {
        return c1._value == c2._value;
    }

    public static bool operator !=(ModInt c1, ModInt c2) {
        return !(c1 == c2);
    }

    public static ModInt operator +(ModInt x, ModInt y) {
        return new ModInt(x._value + y._value);
    }
    public static ModInt operator -(ModInt x, ModInt y) {
        return new ModInt(x._value - y._value);
    }
    public static ModInt operator -(ModInt x) {
        return new ModInt(-x._value);
    }
    public static ModInt operator *(ModInt x, ModInt y) {
        return new ModInt(x._value * y._value);
    }
    public static ModInt operator /(ModInt x, ModInt y) {
        return new ModInt(x._value * Inverse(y._value, mod));
    }
    public static ModInt operator ++(ModInt x) {
        return x + 1;
    }
    public static ModInt operator --(ModInt x) {
        return x - 1;
    }
    public static ModInt Pow(ModInt x, long n) {
        ModInt r = 1;
        while (n > 0) {
            if ((n & 1) != 0) {
                r *= x;
            }

            x *= x;
            n >>= 1;
        }
        return r;
    }
    private static long ExtendedGcd(long a, long b, ref long x, ref long y) {
        if (b == 0) {
            x = 1; y = 0;
            return a;
        } else {
            var d = ExtendedGcd(b, a % b, ref y, ref x);
            y -= a / b * x;
            return d;
        }
    }

    private static long Inverse(long a, long mod) {
        long x = 0, y = 0;
        if (ExtendedGcd(a, mod, ref x, ref y) == 1) {
            return (x + mod) % mod;
        } else {
            throw new Exception("Invalid inverse " + a + " " + mod);
        }
    }

    public static implicit operator ModInt(long x) {
        return new ModInt(x);
    }

    public override bool Equals(object obj) {
        if (obj == null) {
            return false;
        }
        return _value.Equals(((ModInt)obj)._value);
    }

    public override int GetHashCode() {
        return _value.GetHashCode();
    }

    public bool Equals(ModInt other) {
        return _value.Equals(other._value);
    }
}

// PREWRITEN CODE BEGINS FROM HERE

static public class StringExtensions {
    static public string JoinToString<T>(this IEnumerable<T> source, string separator = " ") {
        return string.Join(separator, source);
    }
}

internal partial class Solver : Scanner {
    public static void Main() {
#if LOCAL
        byte[] inputBuffer = new byte[1000000];
        var inputStream = Console.OpenStandardInput(inputBuffer.Length);
        using (var reader = new StreamReader(inputStream, Console.InputEncoding, false, inputBuffer.Length)) {
            Console.SetIn(reader);
            new Solver(Console.In, Console.Out).Run();
        }
#else
        using (var writer = new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = false }) {
            Console.SetOut(writer);
            new Solver(Console.In, Console.Out).Run();
            Console.Out.Flush();
        }
#endif
    }

#pragma warning disable IDE0052
    private readonly TextReader cin;
    private readonly TextWriter cout;
    private readonly TextWriter cerr;
#pragma warning restore IDE0052

    public Solver(TextReader reader, TextWriter writer)
        : base(reader) {
        cin = reader;
        cout = writer;
        cerr = Console.Error;
    }

    public Solver(string input, TextWriter writer)
        : this(new StringReader(input), writer) {
    }

#pragma warning disable IDE1006
#pragma warning disable IDE0051
    private int ni() { return NextInt(); }
    private int[] ni(int n) { return NextIntArray(n); }
    private long nl() { return NextLong(); }
    private long[] nl(int n) { return NextLongArray(n); }
    private double nd() { return NextDouble(); }
    private double[] nd(int n) { return NextDoubleArray(n); }
    private string ns() { return Next(); }
    private string[] ns(int n) { return NextArray(n); }
#pragma warning restore IDE1006
#pragma warning restore IDE0051
}

internal static class LinqPadExtension {
    [Conditional("DEBUG")]
    public static void Dump<T>(this T obj) {
#if DEBUG
        LINQPad.Extensions.Dump(obj);
#endif
    }
    [Conditional("DEBUG")]
    public static void DumpString<T>(this T obj) {
#if DEBUG
        LINQPad.Extensions.Dump(obj.ToString());
#endif
    }
}

public class Scanner {
    private readonly TextReader Reader;
    private readonly CultureInfo ci = CultureInfo.InvariantCulture;

    private readonly char[] buffer = new char[2 * 1024];
    private int cursor = 0, length = 0;
    private string Token;
    private readonly StringBuilder sb = new StringBuilder(1024);

    public Scanner()
        : this(Console.In) {
    }

    public Scanner(TextReader reader) {
        Reader = reader;
    }

    public int NextInt() { return checked((int)NextLong()); }
    public long NextLong() {
        var s = Next();
        long r = 0;
        int i = 0;
        bool negative = false;
        if (s[i] == '-') {
            negative = true;
            i++;
        }
        for (; i < s.Length; i++) {
            r = r * 10 + (s[i] - '0');
#if DEBUG
            if (!char.IsDigit(s[i])) throw new FormatException();
#endif
        }
        return negative ? -r : r;
    }
    public double NextDouble() { return double.Parse(Next(), ci); }
    public string[] NextArray(int size) {
        string[] array = new string[size];
        for (int i = 0; i < size; i++) {
            array[i] = Next();
        }

        return array;
    }
    public int[] NextIntArray(int size) {
        int[] array = new int[size];
        for (int i = 0; i < size; i++) {
            array[i] = NextInt();
        }

        return array;
    }

    public long[] NextLongArray(int size) {
        long[] array = new long[size];
        for (int i = 0; i < size; i++) {
            array[i] = NextLong();
        }

        return array;
    }

    public double[] NextDoubleArray(int size) {
        double[] array = new double[size];
        for (int i = 0; i < size; i++) {
            array[i] = NextDouble();
        }

        return array;
    }

    public string Next() {
        if (Token == null) {
            if (!StockToken()) {
                throw new Exception();
            }
        }
        var token = Token;
        Token = null;
        return token;
    }

    public bool HasNext() {
        if (Token != null) {
            return true;
        }

        return StockToken();
    }

    private bool StockToken() {
        while (true) {
            sb.Clear();
            while (true) {
                if (cursor >= length) {
                    cursor = 0;
                    if ((length = Reader.Read(buffer, 0, buffer.Length)) <= 0) {
                        break;
                    }
                }
                var c = buffer[cursor++];
                if (33 <= c && c <= 126) {
                    sb.Append(c);
                } else {
                    if (sb.Length > 0) break;
                }
            }

            if (sb.Length > 0) {
                Token = sb.ToString();
                return true;
            }

            return false;
        }
    }
}