[HNOI2008]明明的烦恼 (Prüfer编码+质因数分解计算两个阶乘的商)
来源:互联网 发布:学通网络红尘老师ps 编辑:程序博客网 时间:2024/05/11 17:10
1005: [HNOI2008]明明的烦恼
Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 3396 Solved: 1346
[Submit][Status][Discuss]
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
HOME Back
以下为转载:http://www.cnblogs.com/noip/archive/2013/03/10/2952520.html
该题运用到了树的prufer编码的性质:
(1)树的prufer编码的实现
不断 删除树中度数为1的最小序号的点,并输出与其相连的节点的序号 直至树中只有两个节点
(2)通过观察我们可以发现
任意一棵n节点的树都可唯一的用长度为n-2的prufer编码表示
度数为m的节点的序号在prufer编码中出现的次数为m-1
(3)怎样将prufer编码还原为一棵树??
从prufer编码的最前端开始扫描节点,设该节点序号为 u ,寻找不在prufer编码的最小序号且没有被标记的节点 v ,连接 u,v,并标记v,将u从prufer编码中删除。扫描下一节点。
该题需要将树转化为prufer编码:
n为树的节点数,d[ ]为各节点的度数,m为无限制度数的节点数。
则
所以要求在n-2大小的数组中插入tot各序号,共有种插法;
在tot各序号排列中,插第一个节点的方法有种插法;
插第二个节点的方法有种插法;
.........
另外还有m各节点无度数限制,所以它们可任意排列在剩余的n-2-tot的空间中,排列方法总数为;
根据乘法原理:
然后就要高精度了.....但高精度除法太麻烦了,显而易见的排列组合一定是整数,所以可以进行质因数分解,再做一下相加减。
关于n!质因数分解有两种方法,第一种暴力分解,这里着重讲第二种。
若p为质数,则n!可分解为 一个数*,其中且 <n
所以
暴力分解:
1 //模仿CLJ大神写的STL,并学会了各种写代码技巧,长见识了! 2 #include<iostream> 3 #include<cstring> 4 #include<string.h> 5 #include<algorithm> 6 #include<cmath> 7 #include<vector> 8 using namespace std; 9 10 int n,nolimit=0,tot=0,ans[10005]={0}; 11 12 vector<int> prime; 13 14 typedef struct{ 15 int h[400]; 16 void Init(){memset(h,0,sizeof(h));} 17 18 void mul(int x){ 19 for(int i=0;i<prime.size();++i) 20 while(x%prime[i]==0) 21 {h[i]++;x/=prime[i];} 22 } 23 void div(int x){ 24 for(int i=0;i<prime.size();++i) 25 while(x%prime[i]==0) 26 {h[i]--;x/=prime[i];} 27 } 28 29 }typenum;typenum sum; 30 31 bool Isprime(int x){ 32 int i; 33 for(i=2;i<=sqrt(x);++i) 34 if(x%i==0) return 0; 35 return 1; 36 } 37 38 void Makeprime(){ 39 for(int i=2;i<=n;++i) 40 if(Isprime(i)) prime.push_back(i); 41 return ; 42 } 43 44 void Init(){ 45 cin>>n; 46 Makeprime(); 47 // for(int i=0;i<prime.size();++i) 48 // cout<<prime[i]<<" ";cout<<endl; 49 sum.Init(); 50 // for(int i=0;i<400;++i) 51 // cout<<sum.h[i]<<" "; 52 int d; 53 for(int i=1;i<=n;++i) 54 { 55 cin>>d; 56 57 for(int i=1;i<d;++i) 58 sum.div(i); 59 if(d==-1)nolimit++;///注意 60 else tot+=d-1;////注意 61 } 62 } 63 64 void Work(){ 65 if(tot>n-2||(tot!=n-2&&nolimit==0)) {cout<<0<<endl;return ;} 66 67 for(int i=1;i<=n-2;++i) 68 sum.mul(i); 69 70 for(int i=1;i<=n-2-tot;++i) 71 sum.div(i); 72 73 for(int i=1;i<=n-2-tot;++i) 74 sum.mul(nolimit); 75 76 ans[0]=1; 77 for(int i=0;i<prime.size();++i) 78 while(sum.h[i]>0) 79 { 80 sum.h[i]--; 81 for(int j=0;j<10000;++j) 82 ans[j]*=prime[i]; 83 84 for(int j=0;j<10000;++j) 85 if(ans[j]>9) 86 {ans[j+1]+=ans[j]/10;ans[j]%=10;} 87 } 88 89 int i=10000; 90 while(ans[i]==0) i--; 91 while(i>=0) cout<<ans[i--]; 92 cout<<endl; 93 } 94 95 int main() 96 { 97 Init(); 98 Work(); 99 // Print();100 // system("pause");101 return 0;102 }
n!质因数特殊分解:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<string.h> 5 #include<cstdlib> 6 #include<cmath> 7 #include<fstream> 8 using namespace std; 9 //ifstream cin("cin.in");10 11 int n,m=0,tot=0,fenmu[1005]={0},fenzi[1005]={0},prime[1005]={0};12 int ans[10005]={0};13 14 void Fenjie(int zz,int a[]){15 int sum;16 for(int i=2;i<=zz;++i)17 if(prime[i])18 {19 sum=i;20 while(sum<=zz)21 {a[i]+=zz/sum;sum*=i;}22 }23 return ;24 }25 26 void Buildprime(){27 int i,j;28 for(i=2;i<=1000;++i)29 {30 for(j=2;j<=sqrt(i);++j)31 if(i%j==0) break; 32 if(j>sqrt(i)) prime[i]=1;//,cout<<i<<" ";33 }//cout<<endl;34 }35 36 int main()37 {38 cin>>n;39 40 Buildprime();41 42 for(int i=1;i<=n;++i)43 {44 int d;45 cin>>d;46 if(d==-1) {m++;continue;}47 if(d>1) Fenjie(d-1,fenmu);48 tot+=d-1;49 }50 51 Fenjie(n-2-tot,fenmu);52 Fenjie(n-2,fenzi);53 54 for(int i=1;i<=1000;++i)55 fenzi[i]-=fenmu[i];56 57 ans[0]=1;58 59 for(int i=1;i<=1000;++i)60 while(fenzi[i]>0)61 {62 fenzi[i]--;63 for(int j=0;j<=10000;++j)64 ans[j]*=i;65 for(int j=0;j<=10000;++j)66 if(ans[j]>9)67 {ans[j+1]+=ans[j]/10;ans[j]%=10;} 68 }69 70 if(m>0)71 for(int i=1;i<=n-2-tot;++i)72 {73 for(int j=0;j<=10000;++j)74 ans[j]*=m;75 for(int j=0;j<=10000;++j)76 if(ans[j]>9)77 {78 ans[j+1]+=ans[j]/10;79 ans[j]%=10;80 }81 }82 83 if(tot>n-2||(tot<n-2&&m==0)) {cout<<0<<endl;return 0;}84 85 int i=10000;86 while(ans[i]==0) i--;87 // if(i<=0) cout<<ans[0];88 while(i>=0) cout<<ans[i--];89 cout<<endl;90 91 // system("pause");92 return 0;93 94 }
最后还要吐槽一句:八中OJ评测不给力啊,就因为ans数组开小了害我检查了一天的WA。
以下为我自己写的代码:
#include<cstdio>#include<cstring>#include<algorithm>#define ms(a) memset(a,0,sizeof(a))using namespace std;const int maxn=1e3;const int len=1e4;int prime[maxn];bool flag[maxn];int n,tot,m;int a[maxn],b[maxn],d[maxn];int ans[maxn];void get_prime(){ int i,j;ms(flag),prime[0]=0; for(i=2;i<maxn;i++) { if(!flag[i])prime[++prime[0]]=i; for(j=1;j<=prime[0] && i*prime[j]<maxn;j++) { flag[i*prime[j]]=1; if(i%prime[j]==0)break;}}}void get_fact(int l,int r){ int x,i,j; for(x=l;l<=r;x=(++l)) for(i=1;x>1;i++)if(x%prime[i]==0) { for(j=0;x%prime[i]==0;x/=prime[i])j++; b[i]+=j; }}void resolve(){ int i,j; ms(a),ms(b); for(i=2;i<=d[0];i++) { if(d[i]!=d[i-1])get_fact(d[i-1]+1,d[i]); for(j=1;j<=prime[0];j++)a[j]+=b[j];} get_fact(d[d[0]]+1,n-2); for(j=1;j<=prime[0];j++)a[j]=b[j]-a[j]; ms(b),get_fact(m,m); for(j=1;j<=prime[0];j++)a[j]+=b[j]*(n-2-tot);}void multi(int x){ int i,last=0; for(i=1;i<=ans[0];i++) { ans[i]=ans[i]*x+last; last=ans[i]/len,ans[i]%=len;} if(last)ans[++ans[0]]=last;}int main(){ //freopen("1.in","r",stdin); int i,j; get_prime(),scanf("%d",&n); for(d[0]=tot=0,i=1;i<=n;i++) { scanf("%d",&j); if(j!=-1)tot+=(d[++d[0]]=j-1);} m=n-d[0],d[++d[0]]=0,d[++d[0]]=n-2-tot; sort(d+1,d+d[0]+1); resolve(); ans[0]=1,ans[1]=1; for(i=1;i<=prime[0];i++) for(j=1;j<=a[i];j++) multi(prime[i]); printf("%d",ans[ans[0]]); for(i=ans[0]-1;i>=1;i--) printf("%04d",ans[i]); return 0;}
0 0
- [HNOI2008]明明的烦恼 (Prüfer编码+质因数分解计算两个阶乘的商)
- 1005: [HNOI2008]明明的烦恼 (prufer编码,排列组合,质因数分解,高精度)
- [bzoj1005]:[HNOI2008]明明的烦恼(prufer序列+质因数分解+高精乘)
- [HNOI2008]明明的烦恼
- [HNOI2008] 明明的烦恼
- bzoj1005: [HNOI2008]明明的烦恼
- bzoj1005【hnoi2008】明明的烦恼
- BZOJ1005[HNOI2008]明明的烦恼
- 1005: [HNOI2008]明明的烦恼
- bzoj1005: [HNOI2008]明明的烦恼
- 【BZOJ1005】【HNOI2008】明明的烦恼
- [BZOJ1005][HNOI2008]明明的烦恼
- BZOJ1005: [HNOI2008]明明的烦恼
- 【bzoj1005】[HNOI2008]明明的烦恼
- BZOJ1005: [HNOI2008]明明的烦恼
- bzoj1005: [HNOI2008]明明的烦恼
- 1005: [HNOI2008]明明的烦恼
- [bzoj1005][HNOI2008]明明的烦恼
- java正则表达式
- 第一个JAVA程序解析
- Xen入门系列三【Xen 管理工具 xm】
- matlab GUI如何实现参数传递
- Cocos2D将v1.0的tileMap游戏转换到v3.4中一例(二)
- [HNOI2008]明明的烦恼 (Prüfer编码+质因数分解计算两个阶乘的商)
- Parcelable与Serializable区别
- action重新跳转其它路由
- [HDU 2312]Cliff Climbing[BFS]
- 透视网络空间思路
- 1010. Zipper
- jdk1.8 hashmap
- 多并发下数据保存的问题
- 24.界面间的传值