您的位置:首页 > Web前端

【BZOJ1005】明明的烦恼(HNOI2008)-Prufer序列+组合计数+高精度

2017-11-30 20:34 459 查看
测试地址:明明的烦恼

做法:本题需要用到Prufer序列+组合计数+高精度。

这题就是HNOI2004-树的计数(BZOJ1211)的一个加强版,数据范围增大了,有些点还没有度数限制。但是我们也可以用类似的思路推出答案。我写的BZOJ1211题解看这里

首先,Prufer序列中某些点的出现次数已经确定了,那么这些点之间的排列数量是一个可重排列,设一共有t个点出现次数已经确定,不妨设这些点为1~t,s为这些点的出现次数之和,那么这些点之间的排列数量显然为s!/∏ti=1(di−1)!,而这些排列在整个序列中的出现位置有Csn−2那么多种,而剩下的n−2−s个位置可以从t+1~n,共n−t个点中任选,所以最后的答案为:

[s!/∏ti=1(di−1)!]×Csn−2×(n−t)n−2−s

稍微化一下式子可得:

[(n−2)!/[(n−2−s)!∏ti=1(di−1)!]]×(n−t)n−2−s

然后用和我写的BZOJ1211的题解中类似的处理方法算出最后答案质因数分解的结果,乘起来算出答案即可。由于答案可能很大,所以需要用到高精度计算。最后还要注意判断一下无解,有两种情况是无解的:1.n≠1而某个di=0;2.s>n−2。这样就可以解决此题了。

以下是本人代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
using namespace std;
int n,d[2010],tot=0,t=0,a[2010][2010],sum[2010][2010],ans[2010],final[3010]={0},digit;
ll p[2010];
bool prime[2010]={0};

void calc_prime(int limit)
{
for(ll i=2;i<=limit;i++)
{
if (!prime[i]) p[++tot]=i;
for(ll j=1;j<=tot&&i*p[j]<=limit;j++)
{
prime[i*p[j]]=1;
if (i%p[j]==0) break;
}
}
}

void mult(int x)
{
for(int i=1;i<=digit;i++)
final[i]*=x;
for(int i=1;i<=digit;i++)
if (final[i]>9)
{
final[i+1]+=final[i]/10;
final[i]%=10;
if (i==digit) digit++;
}
}

int main()
{
scanf("%d",&n);
calc_prime(2000);
for(int i=2;i<=2000;i++)
{
for(int j=1;j<=tot;j++)
{
sum[i][j]=0;
int x=i;
while(x%p[j]==0) sum[i][j]++,x/=p[j];
a[i][j]=sum[i][j];
sum[i][j]+=sum[i-1][j];
}
}

int s=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&d[i]);
if (d[i]!=-1) s+=d[i]-1,t++;
if (n!=1&&d[i]==0) {printf("0");return 0;}
}

if (s>n-2) printf("0");
else
{
for(int i=1;i<=tot;i++) ans[i]=sum[n-2][i];
for(int i=1;i<=n;i++)
if (d[i]!=-1)
{
for(int j=1;j<=tot;j++)
ans[j]-=sum[d[i]-1][j];
}
for(int i=1;i<=tot;i++)
ans[i]-=sum[n-2-s][i];
for(int i=1;i<=tot;i++)
ans[i]+=(n-2-s)*a[n-t][i];
final[1]=1,digit=1;
for(int i=1;i<=tot;i++)
for(int j=1;j<=ans[i];j++)
mult(p[i]);
bool flag=0;
for(int i=digit;i>=1;i--)
{
if (final[i]) flag=1;
if (flag) printf("%d",final[i]);
}
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: