題目
分析
令 爲規定了度數的點的個數, ,先考慮規定度數的點的方案數,就是一個重排列乘上選位置的方案數: 再考慮沒規定度數的點,隨便安排,所以總方案數爲 要用高精度。我不太會寫除法,就把每個數分解質因數用類似於取對數優化的方法,最後只用算一次高精度乘法就行了。階乘分解質因數可以 求,但 沒必要,暴力打出 的分解質因數的表就行了。總複雜度略大於 。
注意判斷爲 的情況有兩個:
- 某 ;
- (因爲 就是受限的邊數)。
錯因
- 沒有判斷 的情況;
- 高精度數乘
int
都寫掛了:一次只考慮了進一位,實際上可能進兩位(小於 的最大質數是三位數)……
代碼
#include <bits/stdc++.h>
const int MAXN = 1000;
int N, D[MAXN + 5];
int Div[MAXN + 5][MAXN + 5];
std::vector<int> Pos[MAXN + 5];
void Mul(int *cur, int x, int inv) {
for (int i = 0; i < int(Pos[x].size()); i++) {
int num = Pos[x][i];
if (inv) cur[num] -= Div[x][num];
else cur[num] += Div[x][num];
}
}
void Fac(int *cur, int n, int inv) {
for (int i = 2; i <= n; i++)
Mul(cur, i, inv);
}
int Res[MAXN * MAXN + 5], M;
void NumMul(int *num, int &len, int x) {
for (int i = 1, d = 0; i <= len + 2; i++)
num[i] = num[i] * x + d, d = num[i] / 10, num[i] %= 10;
len += 2;
}
int main() {
scanf("%d", &N);
for (int i = 1; i <= N; i++) {
int tmp = i;
for (int j = 2; j * j <= i; j++) {
while (tmp % j == 0)
Div[i][j]++, tmp /= j;
if (Div[i][j])
Pos[i].push_back(j);
}
if (tmp != 1)
Div[i][tmp] = 1, Pos[i].push_back(tmp);
}
int S = 0, C = 0;
for (int i = 1; i <= N; i++) {
scanf("%d", &D[i]);
if (!D[i])
return puts("0"), 0;
if (~D[i])
S += (D[i] - 1), C++;
}
if (S > N - 1)
return puts("0"), 0;
int *Ans = Div[0];
Fac(Ans, N - 2, 0);
for (int i = 1; i <= N - 2 - S; i++)
Mul(Ans, N - C, 0);
Fac(Ans, N - 2 - S, 1);
for (int i = 1; i <= N; i++)
if (~D[i])
Fac(Ans, D[i] - 1, 1);
Res[M = 1] = 1;
for (int i = 1; i <= N; i++) {
while (Ans[i]--)
NumMul(Res, M, i);
}
while (M > 1 && !Res[M])
M--;
for (int i = M; i >= 1; i--)
putchar(Res[i] + '0');
return 0;
}