有趣的数列 唯一分解定理+卡特兰数

问题:
我们称一个长度为\(2n\)的数列是有趣的,当且仅当该数列满足以下三个条件:

(1)它是从\(1\)\(2n\)\(2n\)个整数的一个排列{\(Ai\)};

(2)所有的奇数项满足\(A1<A3<…<A2n-1\),所有的偶数项满足\(A2<A4<…<A2n\)

(3)任意相邻的两项\(A2i-1\)\(A2i(1≤i≤n)\)满足奇数项小于偶数项,即:\(A2i-1<A2i\)

现在的任务是:对于给定的\(n\),请求出有多少个不同的长度为\(2n\)的有趣的数列。因为最后的答案可能很大,所以只要求输出答案\(mod P\)的值。

解:
$1 2 5 14 42 $
奇数小于偶数 \(入栈>=出栈\) 这是一个卡特兰数

我们应该用 一下公式求解
$ \frac {c_{2n}^n}{n+1}$ =\(\frac {2n!} {n!*n!}\)*\(\frac {1} {n+1}\)=\(\prod_{n+2}^{2**n}\)

但是这道题还是没有完
你会发现它模数不一定是质数 所以你要用扩展lucas

好吧其实是唯一分解定理来进行约分

虽然我不知道为什么 可以约分
开先我对于每个质因数筛次数 \(T 50\)
经过hyh 的指点
我才发现 可以从后往前讨论 对每个数进行分解 \(sqrt\)级别

code:

#include<stdio.h>
#include<iostream>
using namespace std;
#define maxnn 2000100
#define ll long long
ll zhi[maxnn];
ll n,p;
ll phi[maxnn];
ll cnt[maxnn];
ll len=0;
ll is[maxnn];
void init()
{
    phi[1]=1;
    for(ll i=2;i<=2000000;i++)
    {
        if(!phi[i])
            zhi[++len]=i;
        for(int j=1;j<=len&&zhi[j]*i<=2000000;j++)
        {
            phi[zhi[j]*i]=1;
            if(i%zhi[j]==0) break;
        }
    }
}
void iiit(){
  
    for(ll i=2*n;i>=1;i--)
    {
        if(is[i])
    {
        if(zhi[lower_bound(zhi+1,zhi+len+1,i)-zhi]==i) continue;
        for(int j=2;j*j<=i;j++)
        {
            if(i%j==0)
            {
                is[j]+=is[i];
                is[i/j]+=is[i];
                break;
            }
        }
    }
    }
    for(int i=1;i<=len&&zhi[i]<=2*n;i++)
    {
        if(is[zhi[i]]) cnt[zhi[i]]+=is[zhi[i]];
    }
}
ll ksm(ll a,ll b)
{
    ll ans=1;
    while(b)
    {
        if(b&1) ans=ans*a%p;
        a=a*a%p;
        b>>=1;
    }
    return ans;
}
int main(){
    cin>>n>>p;
    for(ll i=n+2;i<=2*n;i++) is[i]=1;
    for(ll i=1;i<=n;i++) is[i]=-1;
    init();
    iiit();
    ll tot=1;
    for(ll i=1;i<=len&&zhi[i]<=2*n;i++)
    {
        if(cnt[zhi[i]]) tot=tot*ksm(zhi[i],cnt[zhi[i]])%p;
    }
    cout<<tot%p;
}
posted @ 2019-09-10 00:02  ALEZ  阅读(303)  评论(0编辑  收藏  举报