【BZOJ1005】【HNOI2008】明明的烦恼
又是看黄学长的代码写的,估计我的整个BZOJ平推计划都要看黄学长的代码写
原题:
自从明明学了树的结构,就对奇怪的树产生了兴趣......给出标号为1到N的点,以及某些点最终的度数,允许在
任意两点间连线,可产生多少棵度数满足要求的树?
0 < N < = 1000
这题用到了树的prufer编码
prufer编码是什么呐
注意下面扯到的树都是无根树(下面不少定义是从黄学长哪里直接粘过来的)
每次删除树中度数为1且序号最小的节点,并在序列中添加与其相邻的节点的序号,直到树中有两个节点,手玩一组小数据很容易理解(逃
呢么任意一棵树都有唯一的长度为n-2的prufer编码,且度数为m的节点在编码中出现了m-1次
呢么就可以将编码还原回一棵树,从prufer编码的最前端开始扫描节点,设该节点序号为 u ,寻找不在prufer编码的最小序号且没有被标记的节点 v ,连接 u,v,并标记v,将u从prufer编码中删除。扫描下一节点。
题中已经把度数给了,呢么就用prufer编码解决
不会写数学表达式,直接粘黄学长的解释吧(sro_hzwer_orz)
题目很丧心病狂的没有让膜一个数,所以要高精度
然而如果用高精度除就亏了,因为这个式子求的是方法数,最后肯定是个整数,呢么就可以分解质因数然后加减,最后再高精度乘
高精度乘可以使用万进制优化,这里有个小技巧,scanf("%abd");表示输出b位数,不够的部分前面补a
因为高精度乘WA了5次,实力会随着时间的推移而减弱qaq
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 using namespace std; 7 int mo=100000; 8 int n,a[1100]; 9 int m=0,tot=0; 10 int zhi[110000],ztop=0; 11 bool kang[510000]; 12 int num[110000]; 13 int ans[1100000],la=0; 14 void shai(){ 15 memset(kang,0,sizeof(kang)); 16 for(int i=2;i<=500000;i++)if(!kang[i]){ 17 zhi[++ztop]=i; 18 int temp=2; 19 while(i*temp<=500000){ 20 kang[i*temp]=true; 21 temp++; 22 } 23 } 24 } 25 void buff(int x,int y){//hzwer_orz,用一个参数可以将加和减的代码合并 26 for(int i=1;i<=x;i++){//阶乘 27 int c=i; 28 for(int j=1;c>=zhi[j];j++) 29 while(!(c%zhi[j])){ 30 num[j]+=y; 31 c/=zhi[j]; 32 } 33 } 34 } 35 void mul(int x){ 36 for(int i=1;i<=la;i++) ans[i]*=x; 37 for(int i=1;i<=la;i++){ 38 ans[i+1]+=ans[i]/mo; 39 ans[i]%=mo; 40 } 41 while(ans[la+1]){ la++; ans[la+1]+=ans[la]/mo; ans[la]%=mo;} 42 } 43 int main(){ 44 //freopen("ddd.in","r",stdin); 45 //freopen("bzoj_1005.in","r",stdin); 46 //freopen("bzoj_1005.out","w",stdout); 47 memset(num,0,sizeof(num)); 48 shai(); 49 cin>>n; 50 if(n==1){ 51 scanf("%d",&a[1]);//注意因为a要--,所以这个特判不能放下面 52 if(!a[1] || a[1]==-1) cout<<1<<endl; 53 else cout<<0<<endl; 54 return 0; 55 } 56 for(int i=1;i<=n;i++){ 57 scanf("%d",&a[i]); 58 if(!a[i]){ cout<<0<<endl; return 0;} 59 if(a[i]==-1) m++; 60 else a[i]--,tot+=a[i]; 61 } 62 buff(n-2,1); 63 buff(n-2-tot,-1); 64 for(int i=1;i<=n;i++)if(a[i]) buff(a[i],-1); 65 ans[la=1]=1; 66 for(int i=1;i<=ztop;i++) 67 while(num[i] --> 0)//趋向于 68 //mul(num[i]);静态差错多重要?这是第二个傻逼错误了 69 mul(zhi[i]); 70 for(int i=1;i<=n-2-tot;i++) 71 mul(m); 72 //for(int i=1;i<=la;i++) cout<<ans[i]<<" "; cout<<endl; 73 cout<<ans[la];//之前写成最后输出ans[1] qaq 74 for(int i=la-1;i>=1;i--) printf("%05d",ans[i]);//之前写成2到la了,实力会随着时间的推移而降低qaq,然后还是之前写成%04 qaq 75 cout<<endl; 76 //因为高精度乘WA了5次QAQ 77 return 0; 78 }