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;
}