您的位置:首页 > Web前端

bzoj1005 [HNOI2008]明明的烦恼 prufer+组合数学

2018-01-30 17:15 369 查看
直接考虑prufer序列,每个度数-1就是再n-2的序列中出现的次数

对于不确定的-1,每个没有填的位置都是有可能填的,所以直接离散用乘法原理

对于确定的就是组合数选位置,注意要开高精

对于高精除法的话就使用类似exlucas的方法提取因子,最后再乘

码:

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
int ans[1999999],daan[1999999],i,j,n,lin,x,wz,jw,gs[1005][1005],cnt,k;
vector<int>v[1005];
void C(int a,int b)
{
int i,j;
if(b-a>a)
{
for(i=b;i>b-a;i--)
{
for(j=0;j<v[i].size();j++)
ans[v[i][j]]+=gs[i][v[i][j]];
}
for(i=1;i<=a;i++)
{ for(j=0;j<v[i].size();j++)
ans[v[i][j]]-=gs[i][v[i][j]];
}
}else
{
for(i=b;i>a;i--)
{
for(j=0;j<v[i].size();j++)
ans[v[i][j]]+=gs[i][v[i][j]];
}
for(i=1;i<=b-a;i++)
{ for(j=0;j<v[i].size();j++)
ans[v[i][j]]-=gs[i][v[i][j]];
}
}
}
int main()
{
scanf("%d",&n);
for(i=1;i<=n;i++)
{int lin2=i;
for(j=2;j*j<=n;j++)
{
if(lin2%j==0){lin=0;while(lin2%j==0)lin++,lin2/=j; gs[i][j]=lin;v[i].push_back(j);}
}
if(lin2!=1)gs[i][lin2]=1,v[i].push_back(lin2);
}
wz=n-2;
for(i=1;i<=n;i++)
{
scanf("%d",&x);
if(x!=1){
if(x==-1)++cnt;
else C(x-1,wz),wz-=(x-1);
}
}
daan[0]=1;
daan[1]=1;
ans[cnt]+=wz;
for(i=1;i<=n;i++)
{
for(j=1;j<=ans[i];j++)
{
for(k=1;k<=daan[0];k++)
{
long long o=jw+daan[k]*i;
daan[k]=o%1000;
jw=o/1000;
}
while(jw)daan[++daan[0]]=jw%1000,jw/=1000;
}
}
for(i=daan[0];i>=1;i--)
{
if(i!=daan[0])
{
if(daan[i]<100)printf("0");
if(daan[i]<10)printf("0");
}
printf("%d",daan[i]);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: