BZOJ 1005 [HNOI2008]明明的烦恼 purfer序列,排列组合
1005: [HNOI2008]明明的烦恼
Description
自从明明学了树的结构,就对奇怪的树产生了兴趣......给出标号为1到N的点,以及某些点最终的度数,允许在
任意两点间连线,可产生多少棵度数满足要求的树?
Input
第一行为N(0 < N < = 1000),
接下来N行,第i+1行给出第i个节点的度数Di,如果对度数不要求,则输入-1
Output
一个整数,表示不同的满足要求的树的个数,无解输出0
Sample Input
3
1
-1
-1
1
-1
-1
Sample Output
2
HINT
两棵树分别为1-2-3;1-3-2
Source
题解:
n为树的节点数,d[ ]为各节点的度数,m为无限制度数的节点数。
则 ![](//images0.cnblogs.com/blog/352557/201303/10130125-6ff55699a32e47c1bef586bce5ac7fd6.gif)
![](http://images0.cnblogs.com/blog/352557/201303/10130125-6ff55699a32e47c1bef586bce5ac7fd6.gif)
所以要求在n-2大小的数组中插入tot各序号,共有
种插法;
![](http://images0.cnblogs.com/blog/352557/201303/10130355-697de5ca1cbe45ada8135c81e0f00cf9.gif)
在tot各序号排列中,插第一个节点的方法有
种插法;
![](http://images0.cnblogs.com/blog/352557/201303/10130808-1824e74b03a34fa895344fde2f460775.gif)
插第二个节点的方法有
种插法;
![](http://images0.cnblogs.com/blog/352557/201303/10130943-5c2c2bd982cb4232907d547a4540d19a.gif)
………
另外还有m各节点无度数限制,所以它们可任意排列在剩余的n-2-tot的空间中,排列方法总数为
;
![](http://images0.cnblogs.com/blog/352557/201303/10131154-3e35c1b96ae4411f844154aceeb02723.gif)
根据乘法原理:
![](http://images0.cnblogs.com/blog/352557/201303/10141257-456b1434ec874dcca3cf378a1ab4a1ba.gif)
然后就要高精度了…..但高精度除法太麻烦了,显而易见的排列组合一定是整数,所以可以进行质因数分解,再做一下相加减。
关于n!质因数分解有两种方法,第一种暴力分解,这里着重讲第二种。
若p为质数,则n!可分解为 一个数*
,其中
且
<n
![](http://images0.cnblogs.com/blog/352557/201303/10135345-824d3eb9783c4a108bc7159f23703906.gif)
![](http://images0.cnblogs.com/blog/352557/201303/10135036-d928787e8c1144218d2ced568b516c44.gif)
![](http://images0.cnblogs.com/blog/352557/201303/10135639-98a9051a8d504c7b909a0619a8e05a29.gif)
所以 ![](//images0.cnblogs.com/blog/352557/201303/10140031-6211c4fdb6f4433a8bc0beaeb0e14dfa.gif)
![](http://images0.cnblogs.com/blog/352557/201303/10140031-6211c4fdb6f4433a8bc0beaeb0e14dfa.gif)
——转自怡红公子
#include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> #include<vector> using namespace std; const int N = 1e5+10, M = 1e3+10, mod = 1000000, inf = 1e9+1000; typedef long long ll; int n; int d[N],ans[N]; int cnt[N],len=1; void go_way(int x,int key) { for(int j=2;j*j<=x;j++) { while(x%j==0) { cnt[j]+=key; x/=j; // cout<<j<<endl; } } cnt[x]+=key; } int sum = 0,m; void mul(int x) { for(int i=1;i<=len;i++) ans[i]*=x; for(int i=1;i<=len;i++) { ans[i+1]+=ans[i]/mod; ans[i]%=mod; } while(ans[len+1]>0) {len++;ans[len+1]+=ans[len]/mod;ans[len]%=mod;} } int main() { scanf("%d",&n); if(n==1) { int x; scanf("%d",&x); if(!x) cout<<1; else cout<<0; return 0; } for(int i=1;i<=n;i++) { scanf("%d",&d[i]); if(!d[i]) {cout<<0;return 0;} if(d[i]==-1) m++; else {d[i]--;sum+=(d[i]);} } if(sum > n-2) { cout<<0; return 0; } for(int i=1;i<=n-2;i++) go_way(i,1); for(int i=1;i<=n-2-sum;i++) { go_way(i,-1); } for(int i=1;i<=n;i++) { if(d[i]) for(int j=1;j<=d[i];j++) { go_way(j,-1); } } ans[1] = 1; for(int i=2;i<=n;i++) { for(int j=1;j<=cnt[i];j++) mul(i); } for(int i=1;i<=n-2-sum;i++) mul(m); for(int i=len;i>=1;i--) if(i==len)printf("%d",ans[i]); else printf("%06d",ans[i]); return 0; }