传送门
dp好题。
设
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示
i
i
i个数结尾是
j
j
j且结尾两个数递增的方案数。
那么显然可以对称的定义出
g
[
i
]
[
j
]
g[i][j]
g[i][j]表示
i
i
i个数结尾是
j
j
j且结尾两个数递减的方案数。
那么显然有
f
[
i
]
[
j
]
=
g
[
i
]
[
i
−
j
+
1
]
f[i][j]=g[i][i-j+1]
f[i][j]=g[i][i−j+1](考虑把第一个序列中每个数k都变成i-k+1)
且
A
n
s
=
∑
i
=
1
n
(
f
[
n
]
[
i
]
+
g
[
n
]
[
i
]
)
=
2
∗
∑
i
=
1
n
f
[
n
]
[
i
]
Ans=\sum _{i=1} ^n(f[n][i]+g[n][i])=2*\sum _{i=1} ^nf[n][i]
Ans=∑i=1n(f[n][i]+g[n][i])=2∗∑i=1nf[n][i]
由于
f
[
i
]
[
j
]
=
∑
k
=
1
j
−
1
g
[
i
−
1
]
[
k
]
f[i][j]=\sum _{k=1} ^{j-1} g[i-1][k]
f[i][j]=∑k=1j−1g[i−1][k]
=> f [ i ] [ j ] = ∑ k = 1 j − 1 f [ i − 1 ] [ i − 1 − k + 1 ] f[i][j]=\sum _{k=1} ^{j-1} f[i-1][i-1-k+1] f[i][j]=∑k=1j−1f[i−1][i−1−k+1]
=> f [ i ] [ j ] = ∑ k = 1 j − 1 f [ i − 1 ] [ i − k ] f[i][j]=\sum _{k=1} ^{j-1} f[i-1][i-k] f[i][j]=∑k=1j−1f[i−1][i−k]
=> f [ i ] [ j ] = ∑ k = i − j + 1 i − 1 f [ i − 1 ] [ k ] f[i][j]=\sum _{k=i-j+1} ^{i-1} f[i-1][k] f[i][j]=∑k=i−j+1i−1f[i−1][k]
=> f [ i ] [ j − 1 ] = ∑ k = i − j + 2 i − 1 f [ i − 1 ] [ k ] f[i][j-1]=\sum _{k=i-j+2} ^{i-1} f[i-1][k] f[i][j−1]=∑k=i−j+2i−1f[i−1][k]
=> f [ i ] [ j ] − f [ i ] [ j − 1 ] = f [ i − 1 ] [ i − j + 1 ] f[i][j]-f[i][j-1]=f[i-1][i-j+1] f[i][j]−f[i][j−1]=f[i−1][i−j+1]
=> f [ i ] [ j ] = f [ i ] [ j − 1 ] + f [ i − 1 ] [ ] i − j + 1 f[i][j]=f[i][j-1]+f[i-1][]i-j+1 f[i][j]=f[i][j−1]+f[i−1][]i−j+1
推导真妙啊。
注意要特判只有一个的情况。
以及要用滚动数组优化空间233
代码:
#include<bits/stdc++.h>
#define N 4205
using namespace std;
int f[2][N],p,n,ans=0,tmp=0;
int main(){
scanf("%d%d",&n,&p);
if(n==1)return cout<<1,0;
f[tmp][1]=1;
for(int i=2;i<=n;++i){
tmp^=1;
for(int j=1;j<=i;++j)f[tmp][j]=(f[tmp][j-1]+f[tmp^1][i-j+1])%p;
}
for(int i=1;i<=n;++i){
ans+=f[tmp][i];
if(ans>=p)ans-=p;
}
ans<<=1;
if(ans>=p)ans-=p;
cout<<ans;
return 0;
}