首页 > 代码库 > 【BZOJ1005】【HNOI2008】明明的烦恼
【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] qaq74 for(int i=la-1;i>=1;i--) printf("%05d",ans[i]);//之前写成2到la了,实力会随着时间的推移而降低qaq,然后还是之前写成%04 qaq75 cout<<endl;76 //因为高精度乘WA了5次QAQ77 return 0;78 }
【BZOJ1005】【HNOI2008】明明的烦恼
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。