Solution
统计所有可能的放法,减去不合法情况。
设一共有 (num) 个位置缺失,其中有 (q) 个位置可能不合法。
枚举 (i) ((1≤i≤q)),表示当前有 (i) 个位置不合法。则有 (C(i,q)) 种取法,剩下的数有 ((num-i)!) 种排列方式。注意在组合数时除法要用乘法逆元来代替。
得到公式:(ans+=(-1)^i*C(i,q)*(num-i)!) ((1≤i≤q))
Code
#include <iostream>
#include <cstdio>
#include <cstring>
#define LL long long
using namespace std;
const int N = 2333, mod = 1e9 + 7;
LL n, ans, q = 0, num = 0, a[N], f[N], inv[N], vis[N];
LL poww(LL b, LL p)
{
LL res = 1;
while(p)
{
if(p & 1) res = (res * b) % mod;
b = (b * b) % mod;
p >>= 1;
}
return res % mod;
}
LL C(LL x, LL y) { return ((f[x] * inv[y]) % mod * inv[x - y]) % mod; }
int main()
{
scanf("%lld", &n);
memset(vis, 0, sizeof(vis));
for(int i = 1; i <= n; i++)
{
scanf("%lld", &a[i]);
if(a[i] == -1) num++;
else vis[a[i]] = 1;
}
for(int i = 1; i <= n; i++)
if(a[i] == -1 && vis[i] == 0) q++;
f[0] = 1;
for(int i = 1; i <= n; i++)
f[i] = (f[i - 1] * i) % mod;
inv[n] = poww(f[n], mod - 2);
for(int i = n - 1; i >= 1; i--)
inv[i] = inv[i + 1] * (i + 1) % mod;
inv[0] = 1;
ans = f[num];
for(int i = 1; i <= q; i++)
ans = (ans + ((poww(-1, i & 1) * C(q, i)) % mod * f[num - i]) % mod) % mod;
while(ans < 0) ans += mod;
printf("%lld", ans % mod);
return 0;
}