HYSBZ/BZOJ 1005 [HNOI2008] 明明的烦恼 - Prufer编码&组合数学&高精度 此乃神题!
分析&Solution:
再结合题解,才终于理解怎么回事,大赞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]);
}