P3200 [HNOI2009]有趣的数列 (巧妙转换,卡特兰数,分解质因数取模运算)

49 篇文章 1 订阅
44 篇文章 0 订阅

P3200 [HNOI2009]有趣的数列

分析:
  • 这题是个思维题,通过打表也可以容易发现就是卡特兰数

  • 讲一下,是如何巧妙的转换成卡特兰数的

    由数列满足的三个条件,可以发现第 2 i 2i 2i 位(偶数位)至少也是 2 i 2i 2i,并且 2 i 2i 2i 位之前的数也必然比 2 i 2i 2i 位小

    我也不知怎么讲清楚这个转换(T_T)

    将奇数位的看作入栈,偶数位看作出栈

    然后,现在就是按照数字大小处理顺序了,求合法的序列数量,就是卡特兰数

    就比如 ( 1 , 3 , 2 , 4 , 5 , 6 ) (1,3,2,4,5,6) (1,3,2,4,5,6),就是( 1 1 1入, 2 2 2入, 3 3 3出, 4 4 4出, 5 5 5入, 6 6 6出)

  • 这题的取余数还不一定是质数,所以还要通过分解质因数来写

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int N=2e6+5;
int pri[N], b[N], tot;
void init(int n)
{   
    b[0]=b[1]=1;
    for(int i=2;i<=n;i++)
    {
        if(!b[i]) { pri[++tot]=i; b[i]=i; } 
        for(int j=1;i*pri[j]<=n;j++)
        {
            b[pri[j]*i]=pri[j];
            if(i%pri[j]==0) break;
        } 
    }
}
int ksm(int a,int b,int p)
{
    int ans=1;
    while(b)
    {
        if(b&1) ans=ans*a%p;
        a=a*a%p; b>>=1;
    }
    return ans;
}
int cnt[N];
signed main()
{
    int n,p;
    cin>>n>>p;
    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(b[i]!=i)
        {
            cnt[b[i]]+=cnt[i];
            cnt[i/b[i]]+=cnt[i]; // 向下传递
        }
    }
    int ans=1;
    for(int i=2;i<=2*n;i++)
    {
        if(i==n+1) continue;
        if(b[i]==i)
        {
            ans=ans*ksm(i,cnt[i],p)%p;
        }
    }
    cout<<ans<<endl;
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yezzz.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值