题目大意:
现在有一条
[
1
,
l
]
[1, l]
[1,l] 的数轴,要在上面造
n
n
n 座塔,每座塔的坐标要两两不同,且为整点。塔有编号,且每座塔都有高度,对于编号为
i
i
i 座塔,其高度为
i
i
i。对于一座塔,需要满足它与前面以及后面的塔的距离大于等于自身高度(不存在则没有限制)。问有多少建造方案。答案对
m
m
m 取模。塔不要求按编号为顺序建造。
题解:
考虑给你一个排列怎么算有多少种放法,显然令
S
=
∑
i
=
1
n
−
1
max
(
p
i
,
p
i
+
1
)
S=\sum_{i=1}^{n-1}\max(p_i,p_{i+1})
S=∑i=1n−1max(pi,pi+1),则相当于,若记
x
i
x_i
xi为
p
i
p_i
pi到
p
i
+
1
p_{i+1}
pi+1的距离,则
x
i
≥
max
(
p
i
,
p
i
+
1
)
x_i\ge\max(p_i,p_{i+1})
xi≥max(pi,pi+1),特殊的
min
(
x
0
,
x
n
)
≥
0
\min(x_0,x_n)\ge0
min(x0,xn)≥0,并且
∑
i
=
0
n
x
i
=
L
−
1
\sum_{i=0}^nx_i=L-1
∑i=0nxi=L−1,可知方案数是
(
L
−
1
−
S
+
n
n
)
\binom{L-1-S+n}{n}
(nL−1−S+n)。
因此dp所有排列的S的信息,令dp(i,j,k)表示,从小到大考虑了前i个数字,当前的S是j,并且形成了k段的方案数,转移有三种:单独称为一段,放在某一段的一端,或者合并两端。
由于m不是质数,因此要注意组合数怎么算:注意到C(L-1-S+n,n)的第一维变化范围是
O
(
n
2
)
O(n^2)
O(n2)的,因此先用矩乘跑出
C
(
L
−
1
−
max
S
+
n
,
0
…
n
)
C(L-1-\max S+n,0\dots n)
C(L−1−maxS+n,0…n),然后递推出剩下的即可。
复杂度
O
(
n
4
+
n
3
l
g
L
)
O(n^4+n^3lgL)
O(n4+n3lgL)
#include<bits/stdc++.h>
#define gc getchar()
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define ull unsigned lint
#define db double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline int inn()
{
int x,ch;while((ch=gc)<'0'||ch>'9');
x=ch^'0';while((ch=gc)>='0'&&ch<='9')
x=(x<<1)+(x<<3)+(ch^'0');return x;
}
const int N=110,MXS=10010;
int dp[2][MXS][N],mod;
inline int upd(int &x,int y) { return x+=y,(x>=mod?x-=mod:0); }
namespace Binom_Space{
int u,d,c[MXS][N];
struct matrix{
int v[N][N],n;matrix(int _n=0) { init(_n); }
inline int init(int _n) { n=_n;rep(i,0,n) memset(v[i],0,sizeof(int)*(n+1));return 0; }
inline matrix operator*(const matrix &b)const
{
const matrix &a=*this;matrix c(n);
rep(i,0,n) rep(k,0,n) rep(j,0,n) upd(c.v[i][j],(lint)a.v[i][k]*b.v[k][j]%mod);
return c;
}
inline matrix& operator*=(const matrix &b) { return (*this)=(*this)*b; }
}A;
inline matrix fast_pow(matrix A,int k)
{
matrix ans(A.n);rep(i,0,A.n) ans.v[i][i]=1;
for(;k;k>>=1,A*=A) if(k&1) ans*=A;return ans;
}
inline int getC(int _u,int _d,int n)
{
u=_u,d=_d,A.init(n),A.v[0][0]=1;
rep(i,1,n) A.v[i][i-1]=A.v[i][i]=1;
A=fast_pow(A,u);
rep(i,0,n) c[0][i]=A.v[i][0];
rep(i,1,d-u) c[i][0]=1;
rep(i,1,d-u) rep(j,1,n) c[i][j]=c[i-1][j-1]+c[i-1][j],(c[i][j]>=mod?c[i][j]-=mod:0);
return 0;
}
inline int C(int n,int m) { return c[n-u][m]; }
}using Binom_Space::C;
int main()
{
int n=inn(),L=inn();mod=inn();
int now=1,nxt=0,lwr=0,upr=0;dp[now][0][1]=1;
for(int i=1;i<n;i++,swap(nxt,now))
{
rep(j,0,i*(i+1)) memset(dp[nxt][j],0,sizeof(int)*(i+1+1));
int nxtlwr=i*(i+1),nxtupr=0;
rep(j,lwr,upr) rep(k,1,i) if(dp[now][j][k])
upd(dp[nxt][j][k+1],dp[now][j][k]*(k+1ll)%mod),
upd(dp[nxt][j+i+1][k],dp[now][j][k]*2ll*k%mod),
upd(dp[nxt][j+2*(i+1)][k-1],dp[now][j][k]*(k-1ll)%mod),
nxtlwr=min(nxtlwr,j),nxtupr=max(nxtupr,j+2*(i+1));
lwr=nxtlwr,upr=nxtupr;
}
int u=max(L-1-upr+n,0),d=max(0,L-1-lwr+n),ans=0;
Binom_Space::getC(u,d,n);
rep(s,lwr,upr) if(dp[now][s][1])
upd(ans,(lint)C(L-1-s+n,n)*dp[now][s][1]%mod);
return !printf("%d\n",ans);
}