【BZOJ 1005】[HNOI2008]明明的烦恼(暴力化简法)
【题目链接】:http://www.lydsy.com/JudgeOnline/problem.php?id=1005
【题意】
中文题
【题解】
一棵节点上标有序号的树会和一个prufer数列唯一对应;
这个prufer数列可以这样获得;
每次找到序号最小的叶子节点;
然后把它删掉;
将与之相连的那个点加入数列的尾端;
重复上述操作直到只剩下两个节点为止;
即最后
一棵n个节点的树对应了一个长度为n-2的数列;
eg:
比如说这个图;
最小叶节点为2,删除2,将3计入序列
最小叶节点为4,删除4,将5计入序列
最小叶节点为5,删除5,将1计入序列
最小叶节点为1,删除1,将3计入序列
图中只剩下两个节点,退出
于是得到这棵树的Prufer序列为{3,5,1,3}
容易发现;
序列中某个数字出现的次数,就是它的度数-1;
且一个prufer序列(有序数列)也唯一对应了一棵树;
假设题目所给的n个节点,那些d[i]!=-1的每个节点的所需度数减去1后的总和为tot;
设有特定度数的节点个数为y,然后令没有特殊需要的节点个数为m
这样,我们相当于在n-2个空格当中选择tot个位置去放那些需要的y个节点;
那就是个组合问题了;
先在n-2个空格中选tot个位置;
即C(n-2,tot);······①
然后对于第i个节点,他要在位置里面选d[i]-1个空格放进去;
即
C(tot,d[i]-1]);·····②
然后对于第i+1个节点;
C(tot-(d[i]-1),d[i+1]-1);····③
…
然后将①②③….全部乘起来就是有特殊需求的节点的答案了;
至于剩下的m个没有特殊需求的节点;
在剩余的n-2-tot个位置里面;每个位置都有m个选择;
即m^(n-2-tot);
也乘上去就好;
最后全部乘在一起;
化简后就变为
【m^(n-2-tot)* (n-2)!】/【(n-2-tot)!* (d[1]-1)!*(d[2]-1)!……(d
-1)!】;
因为是方案,所以最后肯定可以约成整数;
所以问题就变成将n!质因数分解了;
(1..n每个数都质因数分解一下);
可以考虑分母和分子对最后结果的质因数分解形式的贡献;
分子的质因子对最后结果的相应质因子的指数的贡献是+1的;
而分母的质因子对最后结果的相应质因子的指数的贡献肯定是-1的;
有几个就减去相应的次数或加上相应的次数就好;
(需要写高精度);
(下一篇有更好的化简方法);
【完整代码】
/************************************************************** Problem: 1005 User: chengchunyang Language: C++ Result: Accepted Time:36 ms Memory:1304 kb ****************************************************************/ #include <bits/stdc++.h> using namespace std; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define LL long long #define rep1(i,a,b) for (int i = a;i <= b;i++) #define rep2(i,a,b) for (int i = a;i >= b;i--) #define mp make_pair #define pb push_back #define fi first #define se second #define rei(x) scanf("%d",&x) #define rel(x) scanf("%I64d",&x) typedef pair<int,int> pii; typedef pair<LL,LL> pll; const int dx[9] = {0,1,-1,0,0,-1,-1,1,1}; const int dy[9] = {0,0,0,-1,1,-1,1,-1,1}; const double pi = acos(-1.0); const int N = 1100; int n,d ,m,tot,cnt ; int ans ,len = 1; void go(int t,int x) { for (int i = 2;i*i<=t;i++) while (t%i==0) { cnt[i]+=x; t/=i; } cnt[t]+=x; } void cheng(int p) { int x = 0; rep1(i,1,len) { ans[i] = ans[i]*p+x; x = ans[i]/10; ans[i]%=10; } while (x>0) { ans[++len] = x; x = ans[len]/10; ans[len]%=10; } } int main() { //freopen("F:\\rush.txt","r",stdin); rei(n); rep1(i,1,n) { rei(d[i]); if (d[i]==0) return puts("0"),0; if (d[i]==-1) m++; else d[i]--,tot+=d[i]; } if (n-2<tot) return puts("0"),0; rep1(i,1,n-2) go(i,1); rep1(i,1,n-2-tot) go(i,-1); rep1(i,1,n) rep1(j,1,d[i]) go(j,-1); ans[1] = 1; rep1(i,2,n) rep1(j,1,cnt[i]) cheng(i); rep1(i,1,n-2-tot) cheng(m); rep2(i,len,1) printf("%d",ans[i]); return 0; }
- 【BZOJ 1005】[HNOI2008]明明的烦恼(化简的另一种方法)
- Prufer编码 & [bzoj 1005] [HNOI2008]明明的烦恼:Prufer编码,组合数学,高精度
- [bzoj1005][HNOI2008][明明的烦恼] (高精度+prufer定理)
- 【BZOJ】1005: [HNOI2008]明明的烦恼(prufer编码+特殊的技巧)
- bzoj1005: [HNOI2008]明明的烦恼
- BZOJ 1005 [HNOI2008] 明明的烦恼
- [BZOJ 1005][HNOI2008]明明的烦恼(prufer编码+组合数学+高精度)
- [bzoj1005][HNOI2008]明明的烦恼
- BZOJ.1005.[HNOI2008]明明的烦恼(Prufer 高精 排列组合)
- [BZOJ1005][HNOI2008]明明的烦恼
- 【组合数学】【高精度】【prufer数列】【HNOI 2008】【bzoj 1005】明明的烦恼
- bzoj 1005: [HNOI2008]明明的烦恼
- 【Prufer编码+组合】BZOJ1005(HNOI2008)[明明的烦恼]题解
- BZOJ 1005 [HNOI2008] 明明的烦恼(组合数学 Purfer Sequence)
- 【bzoj1005】 HNOI2008—明明的烦恼
- BZOJ1005 [HNOI2008]明明的烦恼
- BZOJ 1005: [HNOI2008]明明的烦恼 Purfer数列
- 【BZOJ】【1005】【HNOI2008】明明的烦恼
- 【bzoj 1005】 明明的烦恼 【HNOI2008】
- bzoj 1005: [HNOI2008]明明的烦恼