zoukankan      html  css  js  c++  java
  • 【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 }
    View Code
  • 相关阅读:
    CopyOnWriteArrayList设计思路与源码分析
    点击页面按钮以excel保存到本地
    上传图片
    关于重复点击的
    去首尾空格还有换行问题//把数字换位大写字母//向后台传输数据
    判断输入的时间与当前的时间(判断时间是今天还是以前的)
    前端的一些小技巧
    git 操作大全
    移动web开发常见问题解决方案
    响应式布局
  • 原文地址:https://www.cnblogs.com/JSL2018/p/5913820.html
Copyright © 2011-2022 走看看