Problem Specification | Value |
---|---|
Time Limit | 1 Sec |
Memory Limit | 162 MB |
Submit | 3972 |
Solved | 1579 |
Description
自从明明学了树的结构, 就对奇怪的树产生了兴趣...... 给出标号为 1 到 N 的点, 以及某些点最终的度数, 允许在
任意两点间连线, 可产生多少棵度数满足要求的树?
Input
第一行为 N (0 < N <=1000), 接下来 N 行, 第 i+1 行给出第 i 个节点的度数 Di, 如果对度数不要求, 则输入-1
Output
一个整数, 表示不同的满足要求的树的个数, 无解输出 0
Sample Input
3
1
-1
-1
Sample Output
2
HINT
两棵树分别为 1-2-3; 1-3-2
Source
这题需要了解一种数列:Prufer Sequence
我们知道, 一棵树可以用括号序列来表示, 但是, 一棵顶点标号 (1~ n) 的树, 还可以用一个叫做 Prufer Sequence 的数列表示
一个含有 n 个节点的 Prufer Sequence 有 n-2 个数, Prufer Sequence 中的每个数是 1~ n 中的一个数
一个定理: 一个 Prufer Sequence 和一棵树一一对应
化简之后为:\(res = \frac{(n - 2)!}{(n - 2 - sum)! \times \pi^{cnt}_{i = 1} (d[i] - 1)} \times (n - cnt)^{n - 2 - sum}\)
在有解的情况下, 计算该结果输出就行了
无解的情况非常好确定, 这里就再讨论了
话说为什么调了半天还是在第一个点 WA~
// SAMPLE CODE FROM HZWER
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#define mod 1000000
#define ll long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x*=10;x+=ch-'0';ch=getchar();}
return x*f;
}
int n,m,tot,cnt;
int d[1005],num[1005],pri[1005];
int ans[1005],l=1;
inline bool jud(int x)
{
for(int i=2;i<=sqrt(x);i++)
if(x%i==0)return 0;
return 1;
}
void getpri()
{
for(int i=2;i<=1000;i++)
if(jud(i))pri[++cnt]=i;
}
void solve(int a,int f)
{
for(int k=1;k<=a;k++)
{
int x=k;
for(int i=1;i<=cnt;i++)
{
if(x<=1)break;
while(x%pri[i]==0)
{num[i]+=f;x/=pri[i];}
}
}
}
void mul(int x)
{
for(int i=1;i<=l;i++)
ans[i] = ans[i] * x;
for(int i=1;i<=l;i++)
{
ans[i+1]+=ans[i]/mod;
ans[i]%=mod;
}
while(ans[l+1]>0)
{l++;ans[l+1]+=ans[l]/mod;ans[l]%=mod;}
}
void print()
{
for(int i=l;i>0;i--)
if(i==l)printf("%d",ans[i]);
else printf("%06d",ans[i]);
}
int main()
{
getpri();ans[1]=1;
n=read();
if(n==1)
{
int x=read();
if(!x)printf("1");
else printf("0");
return 0;
}
for(int i=1;i<=n;i++)
{
d[i]=read();
if(!d[i]){printf("0");return 0;}
if(d[i]==-1)m++;
else {d[i]--;tot+=d[i];}
}
if(tot>n-2){printf("0");return 0;}
solve(n-2,1);
solve(n-2-tot,-1);
for(int i=1;i<=n;i++)
if(d[i])solve(d[i],-1);
for(int i=1;i<=cnt;i++)
while(num[i]--)
mul(pri[i]);
for(int i=1;i<=n-2-tot;i++)
mul(m);
print();
return 0;
}
// FALSE CODE, RESERVED FOR DEBUGGING
// FALSE CODE, RESERVED FOR DEBUGGING
// FALSE CODE, RESERVED FOR DEBUGGING
// FALSE CODE, RESERVED FOR DEBUGGING
// FALSE CODE, RESERVED FOR DEBUGGING
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <cstdio>
#include <map>
using namespace std;
const int maxn = 1100, modr = 100000000;
// High precision modules
long long hpdat[maxn];
int hplen = 0;
void hpinit(void) { hplen = 1; hpdat[1] = 1; return ; }
void hpmult(int v)
{
for (int i = 1; i <= hplen; i++) hpdat[i] *= v;
for (int i = 1; i <= hplen; i++) hpdat[i + 1] += hpdat[i] / modr, hpdat[i] %= modr;
if (hpdat[hplen + 1] > 0) hplen++;
return ;
}
void hpprint()
{
cout << hpdat[hplen];
for (int i = hplen - 1; i >= 1; i--)
cout << setfill('0') << setw(8) << hpdat[i];
cout << endl << flush;
return ;
}
// Main program procedure
int n, d[maxn], sum, cnt;
int primes[maxn], primecnt;
map<int, int> facts;
long long result = 0;
void genprimes(void)
{
primecnt = 0;
primes[++primecnt] = 2;
for (int i = 3; i <= maxn; i++) {
bool isprime = true;
for (int j = 1; j <= primecnt && primes[j] * primes[j] < i; j++)
if (i % primes[j] == 0) {
isprime = false;
break;
}
if (!isprime) continue;
primes[++primecnt] = i;
}
facts.clear();
for (int i = 1; i <= primecnt; i++)
facts[primes[i]] = 0;
return ;
}
void factor(int x, int dup)
{
for (int i = 1; i <= maxn && x > 1; i++) {
int p = primes[i], q = 0;
while (x % p == 0) x /= p, q++;
if (!q) continue;
facts[p] += q * dup;
}
return ;
}
int main(int argc, char** argv)
{
scanf("%d", &n);
if (n == 1) {
scanf("%d", &d[1]);
if (d[1] == 0) printf("1\n");
else printf("0\n");
return 0;
}
for (int i = 1; i <= n; i++) {
scanf("%d", &d[i]);
if (d[i] == 0) {
goto no_result;
} else if (d[i] > 0) {
sum += d[i] - 1;
cnt++;
}
}
if (sum > n - 2)
goto no_result;
genprimes();
// Initialize formulae from solution
for (int i = n - 2 - sum + 1; i <= n - 2; i++)
factor(i, 1);
for (int i = 1; i <= n; i++)
if (d[i] != -1)
factor(d[i] - 1, -1);
factor(n - cnt, n - 2 - sum);
// Apply final results to high-precision number
hpinit();
for (int i = 1; i <= primecnt; i++) {
int p = primes[i], q = facts[p];
for (int j = 1; j <= q; j++)
hpmult(p);
}
hpprint();
return 0;
no_result:
printf("0\n");
return 0;
}
from pydatagen import *
n = randrange(1, 1000)
sum = 0
print('%d\n' % n)
for i in range(0, n):
a = randrange(1, 4)
if a + sum < (n - 2) / 2:
sum += a
printf('%d\n' % a)
else:
printf('-1\n')
fclose()