zoukankan      html  css  js  c++  java
  • 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
    ");
            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;
    }
    View Code
  • 相关阅读:
    vue开发chrome扩展,数据通过storage对象获取
    Vue手动集成less预编译器
    Google Translate寻找之旅
    Javascript Range对象的学习
    Javascript Promises学习
    SublimeText 建立构建Node js系统
    We're sorry but demo3 doesn't work properly without JavaScript enabled. Please enable it to continue.
    npm安装包出现UNMET DEPENDENCY报错
    (转载)命令行说明中格式 尖括号 中括号的含义
    Linux重启网卡服务Failed to start LSB: Bring up/down networking.
  • 原文地址:https://www.cnblogs.com/mountaink/p/10433211.html
Copyright © 2011-2022 走看看