P3200 [HNOI2009]有趣的数列

呜呜呜,本蒟蒻第一次做卡特兰数,实在是太菜了。写一个题解加深记忆。

Solution

首先,题里面说明 (a_2<a_4< cdots <a_{2n})(a_{2i-1}<a_{2i}) ,可得偶数位上的数比它前面任意一个数都要大

那么我们可以将题意转化为:将 (1) ~ (2n) 放入这个数列,每次放的数要么放在最前面的奇数位要么放在最前面的偶数位。

你觉得我说的可能是废话

现在说另一个结论:一个数列填入偶数位的个数要时刻不超过填入奇数位的个数

证明:设放在了偶数位上 (a) 个数,放在奇数位上 (b) 个数,并且 (a>b) ,那么现在放了 (a+b) 个数,显然 (a>frac x2=frac {a+b}2) ,并且现在最后一个偶数位的下标(2 imes a) ,但是 (2 imes a>x) ,也就是说不管你在这一位放啥都是不满足条件的。

现在答案就是满足任意位偶位数不超过奇位数的数列个数

(f_{i,j}) 表示填了 (i) 个偶数位, (j) 个奇数位的方案数。递推方程就是 (f_{i,j}=f_{i-1,j}+f_{i,j-1})

最后的答案就是 (f_{n,n})

完结撒花

嘿嘿嘿,如果你算了一下复杂度的话,会发现递推的复杂度是 (O(n^2)) ,显然会T。

上面那个东西,和卡特兰数有很大的关系。其实就是求卡特兰数 (f_n)

所以我们要说关于卡特兰数的几个不一样的公式:

  1. (f_n=sumlimits_{i=0}^{n-1}f_icdot f_{n-i-1}) 这个也是递推的,复杂度依旧不对。
  2. (f_{n}=f_{n-1}cdot frac {4n-2}{n+1}) ,如果 (p) 是质数可以直接使用,也就是这个题。但是这个题没有保证,是做不了了的。
  3. (f_n=frac {C_{2n}^n}{n+1}) ,这个是可以的。

为什么这个就是可以的?因为 (f_n=frac {C_{2n}^n}{n+1}=frac {2n imes (2n-1) imes cdots imes (n+2)}{n!}) ,而一个数又可以表示成 (prod p_i^{k_i}) ,所以我们可以将每个数做质因数分解,统计每个质因子的指数即可。

代码

#include<bits/stdc++.h>
#define ll long long

using namespace std;
const int N=2e6+10;
int min_p[N],p[N],cnt[N],tot,mod,n;

inline int fpow(int a,int b){
    int res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}

inline void init(int n){
    for(int i=2;i<=n;i++){
        if(!min_p[i]) p[++tot]=i,min_p[i]=i;
        for(int j=1;j<=tot&&p[j]*i<=n;j++){
            min_p[i*p[j]]=p[j];
            if(i%p[j]==0) break;
        }
    }
}

int main(){
    scanf("%d%d",&n,&mod);
    init(2*n);
    for(int i=1;i<=n;i++) cnt[i]=-1;
    for(int i=n+2;i<=2*n;i++) cnt[i]=1;
    for(int i=2*n;i>1;i--)
        if(min_p[i]<i) cnt[min_p[i]]+=cnt[i],cnt[i/min_p[i]]+=cnt[i];
    int ans=1;
    for(int i=2;i<=2*n;i++)
        if(min_p[i]==i) ans=(ll)ans*fpow(i,cnt[i])%mod;
    printf("%lld
",ans);
}
原文地址:https://www.cnblogs.com/jasony/p/13843259.html