题目描述
赫尔德想对上面的问题进行探究,她想先做一些统计,于是她抽象了这个问题。
我们对于一个长为 lll 的数列 ppp,定义函数:
- f(p)f(p)f(p) 表示有多少 1≤i≤l1\le i\le l1≤i≤l 满足 pi=maxj=1ipjp_i=\max_{j=1}^i p_jpi=maxj=1ipj(即前缀最大值的个数)。
现在,给定 n,mn,mn,m,请求出有多少满足以下条件的长为 nnn 的,值域在 [m,n][m,n][m,n] 数列 aaa: - 存在一个排列 ppp 使得:令 PiP_iPi 代表 ppp 去掉 pip_ipi 后的数列(即 [p1,p2,…,pi−1,pi+1,…,pn][p_1,p_2,\dots,p_{i-1},p_{i+1},\dots,p_n][p1,p2,…,pi−1,pi+1,…,pn]),f(Pi)=aif(P_i)=a_if(Pi)=ai。
答案对 109+710^9+7109+7 取模。
n,m≤2000n,m\le2000n,m≤2000
题解
玄妙双射题
先考虑m=1m=1m=1怎么做
考虑给aaa序列构造一个双射,我们假设kkk为原排列的前缀最大值个数(可以证明一个aaa只会对应一个kkk,所以不会算重)
ai<ka_i<kai<k说明不合法,pip_ipi不是前缀最大值时,ai=ka_i=kai=k,当pip_ipi时前缀最大值的时,ai∈[k−1,n]a_i\in[k-1,n]ai∈[k−1,n]
分析一下,一个序列中只有333种数,一种是前缀最大值称为红色,一种是删除最靠近它的前缀最大之后会变为前缀最大值称为绿色,一种是无论如何都会变成前缀最大值,称为黄色
我们考虑让一个合法序列aaa唯一对应一个颜色序列
我们用以下操作构造颜色序列
1.首先找到ai≠ka_i\not =kai=k的iii,把该位置染成红色,在它后面需要ai−ka_i-kai−k个绿色,由于它们相对位置并不重要,所以我们钦定后面的绿色紧跟在红色后面,即j∈[i+1,i+ai−k]j\in[i+1,i+a_i-k]j∈[i+1,i+ai−k]的位置会被染成绿色
2.假设我们已经钦定了www个位置为红色,显然我们还需要钦定k−wk-wk−w个红色位置,我们每次找出最小的iii,使得ai=ai+1=ka_i=a_{i+1}=kai=ai+1=k,并且iii和i+1i+1i+1均未被染色,然后把iii染红,i+1i+1i+1染绿,不断进行这个操作k−wk-wk−w遍
3.其余未染色位值均染成黄色
显然一个合法的aaa必定能够对应一个颜色序列,然后一个颜色序列必定能够回推出一个aaa序列,所以合法aaa序列和颜色序列构成双射,且显然对于任意一个颜色序列,我们都可以构造出一个合法的ppp,可以考虑插入构造,所以颜色序列的个数就是合法aaa的个数
直接对颜色序列进行计数
对于颜色序列还有一些隐性限制
1.第一个一定是红,第二个不能为黄
2.x为不为绿的颜色,红绿x前不能出现黄黄,不能出现黄红绿,否则不符合构造颜色序列时的操作2
3.绿紧跟红
根据这三个限制就可以设计状态了,下面是我自己设计的状态
0 黄 无黄黄
1 黄红 无黄黄
2 黄红绿 无黄黄
3 绿 无黄黄 前方不是黄红
4 红 无黄黄 前方非黄
5 黄 有黄黄
6 红 有黄黄
7 红绿 有黄黄
8 绿绿 有黄黄
每行的第二段字表示当前结尾的情况
做m>1m>1m>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;
}