谎言重复一千次就变成真理 回忆重复一|

Day_Dreamer_D

园龄:3年6个月粉丝:3关注:16

2022-05-18 14:14阅读: 29评论: 0推荐: 0

洛谷 P2606 [ZJOI2010]排列计数 分析

分析

题意可以简化为用 [1,n] 的数,组成一个完全二叉树,使其满足小根堆性质,求方案数。

fi 表示在 i 点的方案数,si 表示 i 的子节点个数(包括 i),于是得出递推式:

fi=Csi×2si1×fi2×fi2+1

由于 BZOJ 上 n>m(可能),所以需要用 Lucas 定理。

代码

namespace LZX
{
using namespace std;
#define int long long
const int MAXN=2000015;
int fac[MAXN],s[MAXN],f[MAXN];
int math_qpow(int base,int power,int mod)
{
int res=1;
while(power)
{
if(power&1)
{
res=res*base%mod;
}
base=base*base%mod;
power>>=1;
}
return res;
}
int math_C(int n,int m,int p)
{
return fac[n]*math_qpow(fac[m]*fac[n-m]%p,p-2,p)%p;
}
int math_lucas(int n,int m,int p)
{
if(!m)
{
return 1;
}
if(m>n)
{
return 0;
}
return math_C(n%p,m%p,p)*math_lucas(n/p,m/p,p)%p;
}
int _main()
{
int n,m;
scanf("%lld%lld",&n,&m);
fac[0]=1;
for(int i=1;i<=n;i++)
{
fac[i]=fac[i-1]*i%m;
}
fill(s+1,s+n+1,1);
for(int i=n;i>=2;i--)
{
s[i>>1]+=s[i];
}
fill(f+n+1,f+n*2+2,1);
for(int i=n;i;i--)
{
f[i]=math_lucas(s[i]-1,s[i<<1],m)%m*f[i<<1]%m*f[i*2+1]%m;
}
printf("%lld\n",f[1]);
return 0;
}
}

 

本文作者:Day_Dreamer_D's Blog

本文链接:https://www.cnblogs.com/2020gyk080/p/16284504.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Day_Dreamer_D  阅读(29)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起