赫尔德想对上面的问题进行探究,她想先做一些统计,于是她抽象了这个问题。
我们对于一个长为
l
l
l 的数列
p
p
p,定义函数:
n , m ≤ 2000 n,m\le2000 n,m≤2000
玄妙双射题
先考虑
m
=
1
m=1
m=1怎么做
考虑给
a
a
a序列构造一个双射,我们假设
k
k
k为原排列的前缀最大值个数(可以证明一个
a
a
a只会对应一个
k
k
k,所以不会算重)
a
i
<
k
a_i
分析一下,一个序列中只有
3
3
3种数,一种是前缀最大值称为红色,一种是删除最靠近它的前缀最大之后会变为前缀最大值称为绿色,一种是无论如何都会变成前缀最大值,称为黄色
我们考虑让一个合法序列
a
a
a唯一对应一个颜色序列
我们用以下操作构造颜色序列
1.首先找到
a
i
≠
k
a_i\not =k
ai=k的
i
i
i,把该位置染成红色,在它后面需要
a
i
−
k
a_i-k
ai−k个绿色,由于它们相对位置并不重要,所以我们钦定后面的绿色紧跟在红色后面,即
j
∈
[
i
+
1
,
i
+
a
i
−
k
]
j\in[i+1,i+a_i-k]
j∈[i+1,i+ai−k]的位置会被染成绿色
2.假设我们已经钦定了
w
w
w个位置为红色,显然我们还需要钦定
k
−
w
k-w
k−w个红色位置,我们每次找出最小的
i
i
i,使得
a
i
=
a
i
+
1
=
k
a_i=a_{i+1}=k
ai=ai+1=k,并且
i
i
i和
i
+
1
i+1
i+1均未被染色,然后把
i
i
i染红,
i
+
1
i+1
i+1染绿,不断进行这个操作
k
−
w
k-w
k−w遍
3.其余未染色位值均染成黄色
显然一个合法的 a a a必定能够对应一个颜色序列,然后一个颜色序列必定能够回推出一个 a a a序列,所以合法 a a a序列和颜色序列构成双射,且显然对于任意一个颜色序列,我们都可以构造出一个合法的 p p p,可以考虑插入构造,所以颜色序列的个数就是合法 a a a的个数
直接对颜色序列进行计数
对于颜色序列还有一些隐性限制
1.第一个一定是红,第二个不能为黄
2.x为不为绿的颜色,红绿x前不能出现黄黄,不能出现黄红绿,否则不符合构造颜色序列时的操作2
3.绿紧跟红
根据这三个限制就可以设计状态了,下面是我自己设计的状态
0 黄 无黄黄
1 黄红 无黄黄
2 黄红绿 无黄黄
3 绿 无黄黄 前方不是黄红
4 红 无黄黄 前方非黄
5 黄 有黄黄
6 红 有黄黄
7 红绿 有黄黄
8 绿绿 有黄黄
每行的第二段字表示当前结尾的情况
做
m
>
1
m>1
m>1的情况就要多记两个东西
1.红色的个数
2.是否有红色后面不接绿色
细节挺多
#include
#include
#define ll long long
using namespace std;
const int N=2e3+10,mod=1e9+7;
int n,m;
int f[2][9][N+10][N+10];
void Add(int &a,int b){a+=b;if(a>=mod) a-=mod;}
int main()
{
scanf("%d %d",&n,&m);
n++;
f[0][3][1][2]=1;
f[1][4][2][2]=1;
for(int i=3;i<=n;i++)
for(int j=1;j<=n;j++)
{
for(int k=0;k<=1;k++)
{
Add(f[k][0][j][i],f[k][1][j][i-1]),Add(f[k][0][j][i],f[k][3][j][i-1]),Add(f[k][0][j][i],f[k][4][j][i-1]);
Add(f[k][1][j][i],f[k][0][j-1][i-1]);
Add(f[k][2][j][i],f[k][1][j][i-1]);
Add(f[k][3][j][i],f[k][2][j][i-1]),Add(f[k][3][j][i],f[k][3][j][i-1]),Add(f[k][3][j][i],f[k][4][j][i-1]);
Add(f[k][4][j][i],f[k][1][j-1][i-1]),Add(f[k][4][j][i],f[k][3][j-1][i-1]),Add(f[k][4][j][i],f[k][4][j-1][i-1]);
Add(f[k][5][j][i],f[k][0][j][i-1]),Add(f[k][5][j][i],f[k][5][j][i-1]),
Add(f[k][5][j][i],f[k][6][j][i-1]),Add(f[k][5][j][i],f[k][8][j][i-1]);
Add(f[k][6][j][i],f[k][5][j-1][i-1]),Add(f[k][6][j][i],f[k][6][j-1][i-1]),Add(f[k][6][j][i],f[k][8][j-1][i-1]);
Add(f[k][7][j][i],f[k][6][j][i-1]);
Add(f[k][8][j][i],f[k][7][j][i-1]),Add(f[k][8][j][i],f[k][8][j][i-1]);
}
Add(f[1][0][j][i],f[0][1][j][i-1]),Add(f[1][0][j][i],f[0][4][j][i-1]);
Add(f[1][4][j][i],f[0][4][j-1][i-1]),Add(f[1][4][j][i],f[0][1][j-1][i-1]);
Add(f[1][5][j][i],f[0][6][j][i-1]),Add(f[1][6][j][i],f[0][6][j-1][i-1]);
Add(f[0][0][j][i],mod-f[0][1][j][i-1]),Add(f[0][0][j][i],mod-f[0][4][j][i-1]);
Add(f[0][4][j][i],mod-f[0][4][j-1][i-1]),Add(f[0][4][j][i],mod-f[0][1][j-1][i-1]);
Add(f[0][5][j][i],mod-f[0][6][j][i-1]),Add(f[0][6][j][i],mod-f[0][6][j-1][i-1]);
}
int ans=0;
for(int j=m+1;j<=n;j++)
for(int k=0;k<=1;k++)
Add(ans,f[k][0][j][n]),Add(ans,f[k][5][j][n]);
Add(ans,f[0][0][m][n]),Add(ans,f[0][5][m][n]);
printf("%lld\n",ans);
return 0;
}