P3200-[HNOI2009]有趣的數列【卡特蘭數】

Quant-Ask發表於2020-11-30

正題

題目連結:https://www.luogu.com.cn/problem/P3200


題目大意

求一個長度為 2 ∗ n 2*n 2n的排列要求

  1. 奇數位和偶數位分別遞增
  2. 相鄰的偶數位大於奇數位

解題思路

可以看做是一個 2 ∗ n 2*n 2n的序列按順序填進奇數和偶數位,然後因為第二個要求所以奇數位在任何時候都得比偶數位的要多,就轉換為了求第 n n n個卡特蘭數了。

然後因為 p p p不是質數所以要質因數分解來除數,時間複雜度 O ( n log ⁡ n ) O(n\log n) O(nlogn)


c o d e code code

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2e6+10;
int n,p,tot,pri[N],cnt[N];
bool v[N];
int main()
{
	scanf("%d%d",&n,&p);
	for(int i=2;i<=2*n;i++){
		if(!v[i])pri[++tot]=i;
		for(int j=1;j<=tot&&i*pri[j]<=n;j++){
			v[i*pri[j]]=1;
			if(i%pri[j]==0)break;
		}
	}
	for(int i=n+2;i<=2*n;i++){
		int x=i;
		for(int j=1;pri[j]*pri[j]<=x&&j<=tot;j++)
			while(x%pri[j]==0)x/=pri[j],cnt[j]++;
		if(x!=1)cnt[lower_bound(pri+1,pri+1+tot,x)-pri]++;
	}
	for(int i=1;i<=n;i++){
		int x=i;
		for(int j=1;pri[j]*pri[j]<=x&&j<=tot;j++)
			while(x%pri[j]==0)x/=pri[j],cnt[j]--;
		if(x!=1)cnt[lower_bound(pri+1,pri+1+tot,x)-pri]--;
	}
	long long ans=1;
	for(int i=1;i<=tot;i++)
		while(cnt[i])ans=ans*pri[i]%p,cnt[i]--;
	printf("%d\n",ans);
}

相關文章