bzoj1005: [HNOI2008]明明的烦恼(prufer+高精度)

时间:2023-03-10 00:48:31
bzoj1005: [HNOI2008]明明的烦恼(prufer+高精度)

1005: [HNOI2008]明明的烦恼

题目:传送门

题解:

   毒瘤题啊天~

   其实思考的过程还是比较简单的。。。

   首先当然还是要了解好prufer序列的基本性质啦

   那么和1211大体一致,主要还是利用组合数学:

   首先我们把度数和-n记录为sum,那么根据prufer序列,序列的元素个数就是n-2

   那就是要在n-2个位置中选sum个,然后就是分别根据度数要求算每个元素在sum个位置中的方案,然后乘起来。最后还要乘上没有度数要求的元素的方案数就...ok啦

   思考两分钟...代码两小时...太菜啦!!!!

代码:

 #include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define qread(x) x=read()
using namespace std;
inline int read()
{
int f=,x=;char ch;
while(ch<'' || ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>='' && ch<=''){x=x*+ch-'';ch=getchar();}
return f*x;
}
struct node
{
int len,a[];
node(){memset(a,,sizeof(a));}
}no,n1;
void chengfa(int x)
{
int i;
for(i=;i<=no.len;i++)no.a[i]=no.a[i]*x;
for(i=;i<=no.len;i++)
{
no.a[i+]+=no.a[i]/;
no.a[i]%=;
}
i=no.len;
while(no.a[i+]>)
{
i++;
no.a[i+]+=no.a[i]/;
no.a[i]%=;
}
no.len=i;
while(no.a[no.len]== && no.len>)no.len--;
}
bool pd(int x)
{
if(x<)return false;
double t=sqrt(double(x+));
for(int i=;i<=t;i++)
if(x%i==)
return false;
return true;
}
int n,d[],pr[],s[];
int main()
{
scanf("%d",&n);int cnt=,sum=;
if(n==){qread(d[]);if(d[]){printf("0\n");return ;}else {printf("1\n");return ;}}
for(int i=;i<=n;i++)
{
qread(d[i]);
if(d[i]==){printf("0\n");}
if(d[i]==-)cnt++;
else d[i]-=,sum+=d[i];
}
if(sum>n-){printf("0\n");return ;}
if(sum<n- && cnt==){printf("0\n");return ;}
int len=;
for(int i=;i<=n;i++)if(pd(i))pr[++len]=i;
for(int i=;i<=n-;i++)
{
int x=i;
for(int j=;j<=len;j++)
while(x%pr[j]== && x!=)
s[j]++,x/=pr[j];
}
for(int i=;i<=n--sum;i++)
{
int x=i;
for(int j=;j<=len;j++)
while(x%pr[j]== && x!=)
s[j]--,x/=pr[j];
}
for(int i=;i<=n;i++)
if(d[i]>)
{
for(int k=;k<=d[i];k++)
{
int x=k;
for(int j=;j<=len;j++)
while(x%pr[j]== && x!=)
s[j]--,x/=pr[j];
}
}
no.a[]=;no.len=;
for(int i=;i<=len;i++)
while(s[i]--)
chengfa(pr[i]);
for(int i=;i<=n--sum;i++)chengfa(cnt);
for(int i=no.len;i>=;i--)
printf("%d",no.a[i]);
printf("\n");
return ;
}