【BZOJ 1005】【HNOI 2008】明明的烦恼
http://www.lydsy.com/JudgeOnline/problem.php?id=1005
答案是$$\frac{(n-2)!}{(n-2-sum)!×\prod_{i=1}{cnt}(d[i]-1)!}×(n-cnt)$$
\[sum=\sum_{i=1}^{cnt}(d[i]-1)
\]
用到了prufer编码,参考http://www.cnblogs.com/zhj5chengfeng/p/3278557.html
注意要写高精度!
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 1003;
bool notp[N];
int cnt = 0, n, d[N], num = 0, prime[N], sum = 0, tot[N];
void shai() {
for (int i = 2; i <= n; ++i) {
if (!notp[i]) prime[++num] = i;
for (int j = 1; j <= num && i * prime[j] <= n; ++j) {
notp[i * prime[j]] = true;
if (i % prime[j] == 0)
break;
}
}
}
void add(int x, int flag) {
for (int i = 1; i <= num && x != 1; ++i)
if (x % prime[i] == 0)
while (x % prime[i] == 0) {
tot[i] += flag;
x /= prime[i];
}
}
ll ipow(int x, int b) {
ll w = x, r = 1;
while (b) {
if (b & 1) r *= w;
w = w * w;
b >>= 1;
}
return r;
}
struct Big {
int a[10003], len;
Big() {memset(a, 0, sizeof(a)); len = 0;}
Big operator * (const int &b) const {
Big C;
for (int i = 1; i <= len; ++i) {
C.a[i] += a[i] * b;
C.a[i + 1] += C.a[i] / 10;
C.a[i] %= 10;
}
C.len = len;
while (C.a[C.len + 1] != 0) {
++C.len;
C.a[C.len + 1] = C.a[C.len] / 10;
C.a[C.len] %= 10;
}
return C;
}
};
int main() {
scanf("%d", &n);
int dd;
for (int i = 1; i <= n; ++i) {
scanf("%d", &dd);
if (dd != -1)
d[++cnt] = dd, sum += dd - 1;
}
shai();
if (n == 1) {
puts(dd > 0 ? "0" : "1");
return 0;
}
if (sum > n - 2) {
puts("0");
return 0;
}
int down = n - 2 - sum;
for (int i = n - 2; i > down; --i) add(i, 1);
for (int i = 1; i <= cnt; ++i)
for (int j = d[i] - 1; j > 1; --j)
add(j, -1);
add(n - cnt, down);
Big ans; ans.len = 1; ans.a[1] = 1;
for (int i = 1; i <= num; ++i)
for (int j = tot[i]; j >= 1; --j)
ans = ans * prime[i];
for (int i = ans.len; i >= 1; --i)
putchar('0' + ans.a[i]);
puts("");
return 0;
}
NOI 2017 Bless All