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

直接考虑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]);	
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值