bzoj 1005: [HNOI2008]明明的烦恼 树的prufer序列+万进制
思路:
这道题需要前置知识prufer编码,这篇博客对prufer编码和这道题的分析写的很好。
这里主要讲一些对大数阶乘的分解,一个办法当然是用高精度,上面这篇博客用的是java,还有一个办法是用万进制,但是普通的万进制只能计算乘法,而这里需要用到除法,又不能用逆元(因为没有取模)怎么办呢?
我们发现,上面那篇博客得到的式子是一个组合数的式子,所以必然是整数,如果把分子和分母共同进行质因子分解,那么上面的质因子的数量必然大于下面的,所以我们就把每一个阶乘和数字进行质因子分解,然后对分解出来的质因子用万进制处理(我实际上用的是百万进制)。
代码debug的时候有个很小的地方错了,看了一遍hzwer聚聚的代码,,然后就变默写了。。
#include<bits/stdc++.h> #define clr(a,b) memset(a,b,sizeof(a)) #define fpn() freopen("simple.in","r",stdin) #define rd read() using namespace std; typedef long long ll; inline int read() { int x=0,t=1;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=-1,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return x*t; } const int maxn=1010; int p=1000000; int ans[maxn],num[maxn],pri[maxn],cnt,l,tot; int d[maxn],n,sum; inline bool judge(int x){ for(int i=2;i<=sqrt(x);i++){ if(x%i==0)return false; } return true; } void prim(){ for(int i=2;i<=1000;i++) { if(judge(i))pri[++cnt]=i; } } void resolve(int x,int w){ for(int k=2;k<=x;k++) { int a=k; for(int i=1;i<=cnt;i++){ if(a<=1)break; while(a%pri[i]==0){ num[i]+=w; a/=pri[i]; } } } } void mul(int x){ for(int i=1;i<=l;i++)ans[i]*=x; for(int i=1;i<=l;i++){ ans[i+1]+=ans[i]/p; ans[i]%=p; } while(ans[l+1]>0){ l++; ans[l+1]+=ans[l]/p,ans[l]%=p; } } void print() { for(int i=l;i>0;i--) if(i==l)printf("%d",ans[i]); else printf("%06d",ans[i]); } int main(){ prim(); cin>>n; if(n==1){ int x; cin>>x; if(!x)printf("1\n"); else puts("0"); return 0; } int flag=0; for(int i=1;i<=n;i++) { scanf("%d",&d[i]); if(d[i]!=-1){ if(d[i]==0)flag=1; tot++; sum+=d[i]-1; } } if(sum>n-2||flag){ puts("0"); return 0; } resolve(n-2,1); resolve(n-2-sum,-1); for(int i=1;i<=n;i++){ if(d[i]!=-1){ resolve(d[i]-1,-1); } } ans[++l]=1; for(int i=1;i<=cnt;i++){ while(num[i]--){ mul(pri[i]); } } for(int i=1;i<=n-2-sum;i++){ mul(n-tot); } print(); return 0; }
——愿为泰山而不骄
qq850874665~~