很好的一道思维题。警告:文字较多,没有耐心者勿入。
首先我们命名 a 1 , a 3 , . . . , a 2 n − 1 a_1,a_3,...,a_{2n-1} a1,a3,...,a2n−1为奇数位,其余为偶数位。观察题目条件:奇数位与偶数位上的数字都满足从左到右递增,相邻的 a 2 i − 1 , a 2 i a_{2i-1},a_{2i} a2i−1,a2i满足 a 2 i − 1 < a 2 i a_{2i-1}<a_{2i} a2i−1<a2i。
首先很容易发现,一个偶数位上的数,比它左边的所有偶数位上的数要大,每个偶数位上的数又比它左相邻奇数位上的数要大。这两条信息,我们可以得出,一个偶数位上的数比它左边所有数都要大,那么再概括一下,就是一个偶数位上的数,大于等于这个偶数位的下标。
这个结论并不够我们来得出最后的答案,我们还需要一些结论。
因为数字从左到右,无论奇数位偶数位都满足递增,那么,我们考虑假如我们按 1 − 2 n 1-2n 1−2n的顺序一个一个放数字,我们应该放在哪里?
很容易发现,我们应该放在最靠左的能放的奇数位或者偶数位上,这样才能保证满足递增。
那还有什么限制呢?我们设已经放了 1 − x 1-x 1−x的数, x 1 x_1 x1个放在了奇数位上, x 2 x_2 x2个放在了偶数位上 ( x 1 + x 2 = x ) (x_1+x_2=x) (x1+x2=x)。我们想起前面得出的关于偶数位上放数的结论:一个偶数位上的数,大于等于这个偶数位的下标。那什么时候会小于呢?猜想+估摸一下,感觉是 x 2 > x 1 x_2>x_1 x2>x1??
猜想是很 F a k e Fake Fake的,让我们来简单的证一下。
反证:
假设当前情况为 x 2 > x 1 x_2>x_1 x2>x1,那么显然 x 2 > x / 2 x_2>x/2 x2>x/2,同时最后一个偶数位的下标是 2 × x 2 2\times x_2 2×x2。
因为我们总共只有 x x x个数,但由 x 2 > x / 2 x_2>x/2 x2>x/2我们得知, 2 × x 2 > x 2\times x_2>x 2×x2>x,所以最后一个偶数位不管放什么,都不满足条件,假设不成立。
所以得出结论,按从小到大的顺序放到任意一个数 x x x,都满足放在偶数位上的数字个数小于等于放在奇数位上的数字个数。
想到什么?This
这不是完全一样的卡特兰数吗?但这道题好像更麻烦一点,模数不是质数。那么就需要一些求卡特兰数的技巧,参考别的题解即可,几乎都讲了。
代码:
#include
#define ts cout<<"ok"<
#define oo (1e18)
#define int long long
#define LL unsigned long long
#define hh puts("")
using namespace std;
int n,mo,cnt[2000005],pr[2000005],mn[2000005],top,ans=1;
bool v[2000005];
inline int read(){
int ret=0,ff=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-') ff=-ff;ch=getchar();}
while(isdigit(ch)){ret=(ret<<3)+(ret<<1)+(ch^48);ch=getchar();}
return ret*ff;
}
inline int ksm(int x,int y){
int res=1;
while(y){
if(y&1) res=res*x%mo;
y>>=1;
x=x*x%mo;
}
return res;
}
signed main(){
n=read(),mo=read();
memset(v,1,sizeof(v));
v[1]=0;
for(int i=2;i<=2*n;i++){
if(v[i]){
pr[++top]=i;
mn[i]=i;
}
for(int j=1;j<=top&&pr[j]*i<=2*n;j++){
v[pr[j]*i]=0;
mn[pr[j]*i]=pr[j];
if(i%pr[j]==0) break;
}
}
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>=2;i--){
if(mn[i]<i){
cnt[mn[i]]+=cnt[i];
cnt[i/mn[i]]+=cnt[i];
}
}
for(int i=2;i<=2*n;i++)
if(mn[i]==i)
ans=ans*ksm(i,cnt[i])%mo;
printf("%lld",ans);
return 0;
}