HYSBZ/BZOJ 1005 [HNOI2008] 明明的烦恼 - Prufer编码&组合数学&高精度 此乃神题!

题目描述

分析&Solution:

  1. hzw大神的blog
  2. JMJST大神的blog
  3. Matrix67对Prufer编码的理解

再结合题解,才终于理解怎么回事,大赞hzw大神的blog。

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
#define MAXN 1000
#define INF 200000000
#define MAXL 3000

int n,deg[MAXN+10],cntd,cntp,prime[MAXN+10],tot,fac[MAXN+10];
bool isprime[MAXN+10];
int d[MAXL+10],c[MAXL+10],ans[MAXN+10];

void read()
{
    int x;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&x);
        if(x!=-1){
            deg[++cntd]=x;
            tot+=x-1;
        }
    }
}
void GetPrime(int N)
{
    for(int i=2;i<=N;i++){
        if(!isprime[i])
            prime[++cntp]=i;
        for(int j=1;prime[j]*i<=n&&j<=cntp;j++){
            isprime[prime[j]*i]=true;
            if(i%prime[j]==0)
                break;
        }
    }
}
void Getfac(int x,int f)
{
    int side=sqrt(x+0.5);
    for(int j=1;x&&prime[j]<=side&&j<=cntp;j++)
        if(x%prime[j]==0&&x)
            while(x%prime[j]==0&&x){
                fac[j]+=f;
                x/=prime[j];
            }
    if(x>=2){
        int pos=lower_bound(prime+1,prime+cntp+1,x) - prime;
        fac[pos]+=f;
    }
}
void Multiply(int t)
{
    memset(d,0,sizeof d);
    memset(c,0,sizeof c);
    int L=ans[0]+15;
    for(int i=1;i<=ans[0];i++)
        c[i]=ans[i]*t;
    for(int i=1;i<=L;i++){
        c[i]+=d[i];
        if(c[i]>9){
            d[i+1]+=c[i]/10;
            c[i]%=10;
        }
    }
    while(L>=1&&!c[L]) L--;
    memset(ans,0,sizeof ans);
    ans[0]=L;
    for(int i=1;i<=ans[0];i++)
        ans[i]=c[i];
}
int main()
{
    read();
    GetPrime(MAXN);
    int side=n-2;
    for(int i=2;i<=side;i++)
        Getfac(i,1);
    side=n-2-tot;
    if(side<0){
        printf("0\n");
        return 0;
    }
    for(int i=2;i<=side;i++)
        Getfac(i,-1);
    Getfac(n-cntd,n-2-tot);
    for(int i=1;i<=cntd;i++){
        if(!deg[i]){
            printf("0\n");
            return 0;
        }
        if(deg[i]-1==0) continue;
        for(int j=2;j<=deg[i]-1;j++)
            Getfac(j,-1);
    }
    ans[0]=ans[1]=1;
    bool flag=false;
    for(int i=1;i<=cntp;i++){
        if(fac[i]==0) continue;
        flag=true;
        int k=(log(INF)/log(prime[i]));
        side=abs(fac[i]);
        for(int j=1;j<=side;){
            int t=1;
            for(int p=1;p<=k&&j<=side;p++,j++)
                t*=prime[i];
            Multiply(t);
        }
    }
    if(!flag){
        printf("0\n");
        return 0;
    }
    for(int i=ans[0];i>=1;i--)
        printf("%d",ans[i]);
}
posted @ 2016-02-02 20:56  KatarinaYuan  阅读(117)  评论(0编辑  收藏  举报