【BZOJ1485】[HNOI2009]有趣的数列(组合数学)
生活随笔
收集整理的這篇文章主要介紹了
【BZOJ1485】[HNOI2009]有趣的数列(组合数学)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
【BZOJ1485】[HNOI2009]有趣的數列(組合數學)
題面
BZOJ
洛谷
題解
從小往大填數,要么填在最小的奇數位置,要么填在最小的偶數位置。
偶數位置填的數的個數不能超過奇數位置填的數的個數。
好的,卡特蘭數。
誒,woc,我不會卡特蘭數啊。行,來學一下。
\(H(0)=H(1)=1\)
\(H(n)=\sum_{i=0}^{n-1} H(i)H(n-i-1)\)
\(H(n)=H(n-1)*\frac{4n-2}{n+1}\)
\(H(n)=\frac{C_{2n}^n}{n+1}=C_{2n}^n-C_{2n}^{n+1}\)
前幾項是\(1,1,2,5,14,42,132......\)
我\(NOI\)的時候就因為不會卡特蘭數少得了\(12\)分,菜死。
那么這題直接算分子分母兩個部分的質因子,然后手動除一下再乘,這樣與逆元無關了。
#include<iostream> #include<cstdio> using namespace std; #define MAX 2000100 int n,P,ans=1; int pri[MAX],a[MAX],tot; bool zs[MAX]; void pre(int n) {for(int i=2;i<=n;++i){if(!zs[i])pri[++tot]=i;for(int j=1;j<=tot&&i*pri[j]<=n;++j){zs[i*pri[j]]=true;if(i%pri[j]==0)break;}} } void Divide(int x,int w) {for(int i=1;i<=tot&&pri[i]*pri[i]<=x;++i)while(x%pri[i]==0)x/=pri[i],a[pri[i]]+=w;if(x>1)a[x]+=w; } int fpow(int a,int b) {int s=1;while(b){if(b&1)s=1ll*s*a%P;a=1ll*a*a%P;b>>=1;}return s; } int main() {scanf("%d%d",&n,&P);pre(n+n);Divide(n+1,-1);for(int i=n+n;i>n;--i)Divide(i,1);for(int i=n;i;--i)Divide(i,-1);for(int i=1;i<=n+n;++i)ans=1ll*ans*fpow(i,a[i])%P;printf("%d\n",ans);return 0; }轉載于:https://www.cnblogs.com/cjyyb/p/9768754.html
總結
以上是生活随笔為你收集整理的【BZOJ1485】[HNOI2009]有趣的数列(组合数学)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux日常运维管理技巧(二)Linu
- 下一篇: 动态规划问题中最长公共子序列---C语言