[HNOI2009]有趣的数列(杨氏矩阵+钩子公式)
https://www.luogu.com.cn/problem/P3200
这就是一个2行n列的杨氏矩阵,直接利用钩子公式求解
注意阶乘的质因子分解
单个数质因子分解枚举到根号
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define N 2000001
int mod;
int p[N],v[N],cnt;
int tot[N];
void prep()
{
for(int i=2;i<N;i++)
{
if(!v[i]) p[++cnt]=i;
for(int j=1;j<=cnt;j++)
{
if(p[j]*i>=N) break;
v[p[j]*i]=true;
if(i%p[j]==0) break;
}
}
}
void divide(int x,int y)
{
int xx=sqrt(x);
for(int i=1;i<=cnt && p[i]<=xx;++i)
while(!(x%p[i]))
{
x/=p[i];
tot[i]+=y;
}
if(x>1) tot[lower_bound(p+1,p+cnt+1,x)-p]+=y;
}
int pow(int a,int b)
{
int c=1;
for(;b;b>>=1,a=a*a%mod)
if(b&1) c=c*a%mod;
return c;
}
int main()
{
prep();
int n,t,m;
scanf("%d%d",&n,&mod);
t=n*2;
for(int i=1;i<=cnt && p[i]<=t;++i)
{
m=t;
while(m)
{
tot[i]+=m/p[i];
m/=p[i];
}
}
for(int j=2;j<=n;++j)
divide(1+n-j+1,-2);
divide(n+1,-1);
long long ans=1;
for(int i=1;i<=cnt;++i)
ans=ans*pow(p[i],tot[i])%mod;
printf("%lld",ans);
}