【BZOJ1005】明明的烦恼(HNOI2008)-Prufer序列+组合计数+高精度
2017-11-30 20:34
459 查看
测试地址:明明的烦恼
做法:本题需要用到Prufer序列+组合计数+高精度。
这题就是HNOI2004-树的计数(BZOJ1211)的一个加强版,数据范围增大了,有些点还没有度数限制。但是我们也可以用类似的思路推出答案。我写的BZOJ1211题解看这里。
首先,Prufer序列中某些点的出现次数已经确定了,那么这些点之间的排列数量是一个可重排列,设一共有t个点出现次数已经确定,不妨设这些点为1~t,s为这些点的出现次数之和,那么这些点之间的排列数量显然为s!/∏ti=1(di−1)!,而这些排列在整个序列中的出现位置有Csn−2那么多种,而剩下的n−2−s个位置可以从t+1~n,共n−t个点中任选,所以最后的答案为:
[s!/∏ti=1(di−1)!]×Csn−2×(n−t)n−2−s
稍微化一下式子可得:
[(n−2)!/[(n−2−s)!∏ti=1(di−1)!]]×(n−t)n−2−s
然后用和我写的BZOJ1211的题解中类似的处理方法算出最后答案质因数分解的结果,乘起来算出答案即可。由于答案可能很大,所以需要用到高精度计算。最后还要注意判断一下无解,有两种情况是无解的:1.n≠1而某个di=0;2.s>n−2。这样就可以解决此题了。
以下是本人代码:
做法:本题需要用到Prufer序列+组合计数+高精度。
这题就是HNOI2004-树的计数(BZOJ1211)的一个加强版,数据范围增大了,有些点还没有度数限制。但是我们也可以用类似的思路推出答案。我写的BZOJ1211题解看这里。
首先,Prufer序列中某些点的出现次数已经确定了,那么这些点之间的排列数量是一个可重排列,设一共有t个点出现次数已经确定,不妨设这些点为1~t,s为这些点的出现次数之和,那么这些点之间的排列数量显然为s!/∏ti=1(di−1)!,而这些排列在整个序列中的出现位置有Csn−2那么多种,而剩下的n−2−s个位置可以从t+1~n,共n−t个点中任选,所以最后的答案为:
[s!/∏ti=1(di−1)!]×Csn−2×(n−t)n−2−s
稍微化一下式子可得:
[(n−2)!/[(n−2−s)!∏ti=1(di−1)!]]×(n−t)n−2−s
然后用和我写的BZOJ1211的题解中类似的处理方法算出最后答案质因数分解的结果,乘起来算出答案即可。由于答案可能很大,所以需要用到高精度计算。最后还要注意判断一下无解,有两种情况是无解的:1.n≠1而某个di=0;2.s>n−2。这样就可以解决此题了。
以下是本人代码:
#include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define ll long long using namespace std; int n,d[2010],tot=0,t=0,a[2010][2010],sum[2010][2010],ans[2010],final[3010]={0},digit; ll p[2010]; bool prime[2010]={0}; void calc_prime(int limit) { for(ll i=2;i<=limit;i++) { if (!prime[i]) p[++tot]=i; for(ll j=1;j<=tot&&i*p[j]<=limit;j++) { prime[i*p[j]]=1; if (i%p[j]==0) break; } } } void mult(int x) { for(int i=1;i<=digit;i++) final[i]*=x; for(int i=1;i<=digit;i++) if (final[i]>9) { final[i+1]+=final[i]/10; final[i]%=10; if (i==digit) digit++; } } int main() { scanf("%d",&n); calc_prime(2000); for(int i=2;i<=2000;i++) { for(int j=1;j<=tot;j++) { sum[i][j]=0; int x=i; while(x%p[j]==0) sum[i][j]++,x/=p[j]; a[i][j]=sum[i][j]; sum[i][j]+=sum[i-1][j]; } } int s=0; for(int i=1;i<=n;i++) { scanf("%d",&d[i]); if (d[i]!=-1) s+=d[i]-1,t++; if (n!=1&&d[i]==0) {printf("0");return 0;} } if (s>n-2) printf("0"); else { for(int i=1;i<=tot;i++) ans[i]=sum[n-2][i]; for(int i=1;i<=n;i++) if (d[i]!=-1) { for(int j=1;j<=tot;j++) ans[j]-=sum[d[i]-1][j]; } for(int i=1;i<=tot;i++) ans[i]-=sum[n-2-s][i]; for(int i=1;i<=tot;i++) ans[i]+=(n-2-s)*a[n-t][i]; final[1]=1,digit=1; for(int i=1;i<=tot;i++) for(int j=1;j<=ans[i];j++) mult(p[i]); bool flag=0; for(int i=digit;i>=1;i--) { if (final[i]) flag=1; if (flag) printf("%d",final[i]); } } return 0; }
相关文章推荐
- Prufer编码 & [bzoj 1005] [HNOI2008]明明的烦恼:Prufer编码,组合数学,高精度
- [BZOJ1005][HNOI2008]明明的烦恼(prufer序列+组合数学+高精度)
- BZOJ 1005 [HNOI2008]明明的烦恼 (Prufer编码 + 组合数学 + 高精度)
- 【BZOJ1005/1211】[HNOI2008]明明的烦恼/[HNOI2004]树的计数 Prufer序列+高精度
- 【bzoj1005】[HNOI2008]明明的烦恼 Prufer序列+高精度
- BZOJ_1005_ [HNOI2008]_明明的烦恼_(组合数学+purfer_sequence+高精度+分解因数+快速幂)
- BZOJ 1005: [HNOI2008]明明的烦恼( 组合数学 + 高精度 )
- 1005: [HNOI2008]明明的烦恼 (prufer编码,排列组合,质因数分解,高精度)
- bzoj1005: [HNOI2008]明明的烦恼 [prufer序列]
- BZOJ 1005 [HNOI2008]明明的烦恼 Prufer序列 Python
- [BZOJ1005][HNOI2008]明明的烦恼&&[BZOJ1211][HNOI2004]树的计数【prufer序列】
- [bzoj1005][HNOI2008][明明的烦恼] (高精度+prufer定理)
- HYSBZ/BZOJ 1005 [HNOI2008] 明明的烦恼 - Prufer编码&组合数学&高精度 此乃神题!
- bzoj1005: [HNOI2008]明明的烦恼(prufer数列+高精度)
- bzoj1005 [HNOI2008]明明的烦恼(prufer序列+组合数学+高精)
- bzoj 1005: [HNOI2008]明明的烦恼 prufer编码+高精度
- 【BZOJ 1005】[HNOI2008]明明的烦恼 【Prufer序列】
- [BZOJ1005]HNOI2008 明明的烦恼|prufer编码|排列组合
- 【BZOJ 1005】 1005: [HNOI2008]明明的烦恼 (prufer数列+高精度)
- BZOJ.1005.[HNOI2008]明明的烦恼(Prufer 高精 排列组合)