题目描述
赫尔德想对上面的问题进行探究,她想先做一些统计,于是她抽象了这个问题。
我们对于一个长为
l
l
l 的数列
p
p
p,定义函数:
-
f
(
p
)
f(p)
f(p) 表示有多少
1
≤
i
≤
l
1\le i\le l
1≤i≤l 满足
p
i
=
max
j
=
1
i
p
j
p_i=\max_{j=1}^i p_j
pi=maxj=1ipj(即前缀最大值的个数)。
现在,给定 n , m n,m n,m,请求出有多少满足以下条件的长为 n n n 的,值域在 [ m , n ] [m,n] [m,n] 数列 a a a: - 存在一个排列
p
p
p 使得:令
P
i
P_i
Pi 代表
p
p
p 去掉
p
i
p_i
pi 后的数列(即
[
p
1
,
p
2
,
…
,
p
i
−
1
,
p
i
+
1
,
…
,
p
n
]
[p_1,p_2,\dots,p_{i-1},p_{i+1},\dots,p_n]
[p1,p2,…,pi−1,pi+1,…,pn]),
f
(
P
i
)
=
a
i
f(P_i)=a_i
f(Pi)=ai。
答案对 1 0 9 + 7 10^9+7 109+7 取模。
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<k
ai<k说明不合法,
p
i
p_i
pi不是前缀最大值时,
a
i
=
k
a_i=k
ai=k,当
p
i
p_i
pi时前缀最大值的时,
a
i
∈
[
k
−
1
,
n
]
a_i\in[k-1,n]
ai∈[k−1,n]
分析一下,一个序列中只有
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.是否有红色后面不接绿色
细节挺多
code \text{code} code
#include<cstdio>
#include<algorithm>
#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;
}