您的位置:首页 > 其它

【BZOJ1005】明明的烦恼

2016-04-13 23:45 218 查看
【不看题解一辈子想不出来系列之一】

树的prufer编码,具体内容见黄学长博客。。。
http://hzwer.com/3272.html
实现小技巧就是开全局数组记答案各质因数的次数最后统一乘,只有bign*int 所以可以压位

<del>然而数据规模太小所以我什么优化都没有加

#include<cstdlib>
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
#define maxn 1005
void _read(int &x)
{
x=0; char ch=getchar(); bool flag=false;
while(ch<'0' || ch>'9'){if(ch=='-')flag=1; ch=getchar();}
while(ch>='0' && ch<='9'){x=x*10+ch-'0'; ch=getchar();}
if(flag)x=-x;
return ;
}
int n,cnt,sum,d[maxn],pre_cnt,pre[2*maxn],a[2*maxn],b[2*maxn];
bool v[2*maxn],wrong;
void getpre(int T)//分解质因数的准备工作
{
memset(v,0,sizeof(v));
for(int i=2;i<=T;i++)if(!v[i])
{
pre[++pre_cnt]=i;
for(int j=i;j*i<=T;j++)v[j*i]=1;
}
return ;
}
void Init()
{
wrong=false;
_read(n);
sum=0;cnt=0;
for(int i=1;i<=n;i++)_read(d[i]);

for(int i=1;i<=n;i++)if(d[i]==0){wrong=true;return;}
for(int i=1;i<=n;i++)if(d[i]!=-1){cnt++,sum+=(d[i]-1);}
getpre(2000);
return ;
}
void fj(int now)//将某个数的阶乘唯一分解
{
int t=0;
memset(b,0,sizeof(b));
if(now==1)return ;
for(int i=1;i<=pre_cnt;i++)
{
t=pre[i];
while(t<=now){b[i]+=now/t; t=t*pre[i];}
}
return ;
}
void getC(int x,int y)
{
fj(y);for(int i=1;i<=pre_cnt;i++)a[i]+=b[i];
fj(x);for(int i=1;i<=pre_cnt;i++)a[i]-=b[i];
fj(y-x);for(int i=1;i<=pre_cnt;i++)a[i]-=b[i];
return ;
}
void getA()
{
fj(sum);for(int i=1;i<=pre_cnt;i++)a[i]+=b[i];
for(int j=1;j<=n;j++)if(d[j]-1>0)
{
fj(d[j]-1);
for(int i=1;i<=pre_cnt;i++)a[i]-=b[i];
}
return ;
}
void getPower()
{
memset(b,0,sizeof(b));
if(cnt<n)
{
int t=n-cnt;
for(int i=1;i<=pre_cnt;i++)
{
if(t<=1)break;
while(t%pre[i]==0 && t>0){b[i]++; t=t/pre[i];}
}
for(int i=1;i<=pre_cnt;i++)b[i]*=(n-2-sum);
}
for(int i=1;i<=pre_cnt;i++)a[i]+=b[i];
return ;
}
struct bign
{
int a[4005],n;
bign()
{
memset(a,0,sizeof(a)); n=1; a[1]=1;
}
friend bign operator *(bign x,int y)
{
bign b;
b.n=x.n+5;
for(int i=1;i<=b.n;i++)b.a[i]=x.a[i]*y;
for(int i=1;i<=b.n;i++)if(b.a[i]>=10){b.a[i+1]+=b.a[i]/10; b.a[i]=b.a[i]%10;}
while(b.a[b.n]==0)b.n--;
return b;
}
}ans;
void Output()
{

for(int i=1;i<=pre_cnt;i++)
{
for(int j=1;j<=a[i];j++)ans=ans*pre[i];
}
for(int i=ans.n;i>=1;i--)putchar(ans.a[i]+'0');
putchar('\n');
return ;
}
void work()
{
memset(a,0,sizeof(a));//a数组记录答案中各质因数的次数
//计算组合数
getC(sum,n-2);
//计算可重集排列
getA();
//计算无限制项
getPower();
Output();
return ;
}
int main()
{
freopen("in.txt","r",stdin);
Init();
if(n==1)
{
if(d[1]==0)printf("1\n");
else printf("0\n");
return 0;
}
if(sum<=n-2 && wrong==false)work();
else printf("0\n");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: