当前位置 博文首页 > 文章内容

    Luogu P3200 [HNOI2009]有趣的数列

    作者: 栏目:未分类 时间:2020-08-12 11:00:54

    本站于2023年9月4日。收到“大连君*****咨询有限公司”通知
    说我们IIS7站长博客,有一篇博文用了他们的图片。
    要求我们给他们一张图片6000元。要不然法院告我们

    为避免不必要的麻烦,IIS7站长博客,全站内容图片下架、并积极应诉
    博文内容全部不再显示,请需要相关资讯的站长朋友到必应搜索。谢谢!

    另祝:版权碰瓷诈骗团伙,早日弃暗投明。

    相关新闻:借版权之名、行诈骗之实,周某因犯诈骗罪被判处有期徒刑十一年六个月

    叹!百花齐放的时代,渐行渐远!



    题意

    给定 \(n\),求有多少个长度为 \(2n\) 的排列 \(p\) 满足

    • 对于 \(1\leq i\leq n\)\(p_{2i-1}<p_{2i}\)

    • \(p_1<p_3<\cdots<p_{2n-1},p_2<p_4<\cdots<p_{2n}\)

    答案对给定的模数 \(m\) 取模,不保证 \(m\) 为质数

    \(\texttt{Data Range:}1\leq n\leq 10^6,1\leq m\leq 10^9\)

    题解

    注意到我们可以奇偶分组,最后合并一下。

    接下来考虑将因为一个小于号是 \(2\) 个元素,另一个是 \(n\) 个元素,所以考虑将排列与合法的入栈出栈过程建立映射。

    如果某一个元素入栈了,那么往奇数部分填上这个元素的入栈时间,出栈的话则往偶数部分填。

    由于入栈时间和出栈时间有序,而且弹掉 \(n\) 个元素的时间总比将 \(n\) 个元素入栈的时间晚,所以可以满足所有的限制。

    注意到不同过程的总数就是卡塔兰数,所以答案就出来了。

    但是由于这题需要组合数模合数,所以要对每个数做唯一分解,但是这样是 \(O(n\sqrt{n})\) 的。

    注意到 \(1\sim n\) 中每个质因子对答案的贡献为 \(1\)\(n+1\)\(0\),而 \(n+2\sim 2n\)\(-1\),所以我们需要求出 \(1\sim 2n\) 的所有质因子,这个过程可以仿照埃氏筛来做。

    首先可以枚举一个质数 \(p\),然后枚举他的倍数 \(q\)。接下来不断用 \(q\) 除掉 \(p\),然后顺便对答案产生贡献。容易看出每个数的每个质因子只被考虑到一次,所以复杂度是 \(O(n\log n)\) 的,可以通过。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef int ll;
    typedef long long int li;
    const ll MAXN=1e6+51;
    ll n,MOD,res=1,ptot,tmp,sgn;
    ll np[MAXN<<1],fct[MAXN<<1];
    inline ll read()
    {
        register ll num=0,neg=1;
        register char ch=getchar();
        while(!isdigit(ch)&&ch!='-')
        {
            ch=getchar();
        }
        if(ch=='-')
        {
            neg=-1;
            ch=getchar();
        }
        while(isdigit(ch))
        {
            num=(num<<3)+(num<<1)+(ch-'0');
            ch=getchar();
        }
        return num*neg;
    }
    int main()
    {
        n=read(),MOD=read();
        for(register int i=2;i<=2*n;i++)
        {
            if(!np[i])
            {
                for(register int j=1;i*j<=2*n;j++)
                {
                    np[i*j]=1,tmp=i*j,sgn=i*j<=n?-1:i*j==n+1?0:1;
                    while(tmp%i==0)
                    {
                        fct[i]+=sgn,tmp/=i;
                    }
                }
            }
        }
        for(register int i=2;i<=2*n;i++)
        {
            while(fct[i])
            {
                res=(li)res*i%MOD,fct[i]--;
            }
        }
        printf("%d\n",res);
    }