题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3982
oj自带十倍常数,我也是很服气的
首先我们不难发现,每次选的出去的选手无论是谁,只要AS序列固定,总体的等待时间是不变的,所以,我们可以指定每次选的人是最后进房间的,设第i个卡特兰数为h(i),那么方案总数就是卡特兰数h(n)
然后理性分析一下,肯定是要按照位置算贡献的,对于每一个位置有两种情况,出栈和入栈,假设位置i是出栈的情况,那么我们枚举所有可能的入栈位置j(j<i),很容易发现,假设j与i之间有k个位置,那么如果某个元素从j入栈,从i出栈,那么j和i之间的k的个位置必须满足中间的所有元素入栈一遍,出栈一遍,很显然,k一定是个偶数,而且方案数为h(k/2),然后对于剩下的2*n-k-2个元素,他们的入栈出栈的方案数为h((2*n-k-2)/2),则对于位置i出栈,他的贡献为所有满足条件的k,sigma(h(k/2)*h((2*n-k-2)/2)),同理我们可以得到i为入栈时候的贡献,只不过这时候的贡献是负的。然后我们发现,当我们计算出对于i出栈的所有情况之后,i+2出栈的所有情况只比i出栈的所有情况多了一项,那么我们就可以dp方案数,然后每个位置算贡献就好了。
代码:
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e6+5;
typedef long long ll;
ll a[MAXN*2],b[MAXN*2],f[MAXN],h[MAXN],dp[MAXN*2];
inline ll qpow(int a,int b,int p)
{
ll ret=1;
for(a%=p;b;b>>=1)
{
if(b&1) ret=1LL*ret*a%p;
a=1LL*a*a%p;
}
return ret;
}
void init(int n,int MOD)
{
f[0]=0;f[1]=1;
for(int i=2;i<=n+1;i++)
f[i]=(1LL*((MOD-MOD/i)%MOD)*(f[MOD%i]%MOD))%MOD;
h[0]=1;h[1]=1;
for(int i=2;i<=n;i++)
h[i]=1LL*h[i-1]*(4*i-2)%MOD*f[i+1]%MOD;
}
void solve()
{
int n,p,A,B;
scanf("%d%d%d%d%d",&n,&p,&b[0],&A,&B);
init(n,p);
a[0]=0;
for(int i=1;i<=2*n;i++)
{
b[i]=(1LL*A*b[i-1]+B)%p;
a[i]=a[i-1]+b[i]+1;
}
ll ans=0;
dp[0]=dp[1]=0;
for(int i=2;i<=2*n;i++)
{
int j=(i>>1)-1;
dp[i]=(dp[i-2]+1LL*h[j]*h[n-1-j]%p)%p;
ans=(ans+1LL*a[i]%p*dp[i]%p)%p;
}
for(int i=2*n-1;i>=1;i--)
{
ans=(ans-1LL*a[i]%p*dp[2*n+1-i]%p+p)%p;
}
ans=1LL*ans*qpow(h[n],p-2,p)%p;
printf("%lld\n",(ans+p)%p);
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int T;
scanf("%d",&T);
while(T--)
{
solve();
}
return 0;
}