「LGP8554」心跳
题目
点这里看题目。
对于一个长度为 \(l\) 的序列 \(p\),设 \(f(p)\) 为 \(p\) 的前缀最大值的个数。
对于一个长度为 \(l\) 的排列 \(p\),可以生成一个长度为 \(l\) 的序列 \(a\),其中 \(a_i=f(\overline p_i)\)。此处,\(\overline p_i\) 为 \(p\) 去掉第 \(i\) 个元素后剩下的长度为 \(l-1\) 的序列。
给定正整数 \(n\),求出可以由长度为 \(n\) 的排列生成、最小值 \(\ge m\) 的本质不同的 \(a\) 的数量,答案对于 \(998244353\) 取模。
所有数据满足 \(2\le m\le n\le 2000\)。
分析
不妨先来讨论可以被构造出来的 \(a\) 的充要条件。
我们注意到如果 \(p\) 可以构造出 \(a\),且 \(f(p)=f_0\),则 \(f_0\) 要么为 \(\min a\),要么为 \(1+\min a\),这一点无需多加说明。这导出了两点:
-
我们几乎可以直接枚举 \(f_0\) 来计数。
-
我们需要对于“可以同时被 \(f_0=\min a\) 和 \(f_0=1+\min a\) 构造出来的 \(a\)”做额外处理。
具体来说,我们要么证明不可能出现这样的 \(a\),要么进行去重。
具体走哪一条路,取决于计数条件的难易程度。
放一放第二个问题先。对于 \(a\),尝试在 \(f_0=\min a\) 时进行构造。则可以观察得到:
-
\(p_1\) 一定是前缀最大值。
-
如果某个位置 \(i\) 满足 \(a_i\neq f_0\),则任意一个构造 \(a\) 的排列 \(p\) 中,\(p_i\) 都为前缀最大值。
说明:删除一个不为前缀最大值的位置 \(x\),产生的 \(f(\overline p_x)\) 必然为 \(f_0\)。
-
如果某个位置 \(x\) 满足 \(p_x\) 是前缀最大值,则 \(x+a_x-f_0+1\le n\) 且 \([x,x+a_x-f_0+1]\) 范围内只有 \(x\) 一个位置为前缀最大值。
说明:删除 \(p_x\) 后,原序列至少有 \(f_0-1\) 个前缀最大值,而 \(a_i-f_0+1\) 个新来的前缀最大值必然出现在 \(x\) 和下一个前缀最大值之间。
这意味着,满足 \(i=1\) 或 \(a_i\neq f_0\) 的位置必然会被选为前缀最大值,此外可能还需要加入一些 \(a_x=f_0\) 的位置作为前缀最大值,以满足 “\(f_0\) 个前缀最大值的要求”;钦定为前缀最大值的位置 \(x\) 相当于将 \([x,x+a_x-f_0+1]\) 的位置绑定为一段,且一个位置不能被绑定在两段以内。可以发现这也是充分的。
注意到,“必然前缀最大值产生的段”的结构和 \(a\) 构成了双射,所以我们可以对其进行计数,并满足上述条件。枚举的思路是:确定必然前缀最大值的结构;段之间可以插入 \(f_0\),这样的位置就有 \(t\) 个,对于每一个可以插入 \(f_0\) 的位置,枚举其插入的 \(f_0\) 的个数的奇偶性;枚举有多少个长度为 \(2\) 的 \(f_0\) 的段。于是,可以写出答案为:
其中 \(k\) 就是在枚举长度为 \(2\) 的段的数量。后面的生成函数描述了除了长度为 \(2\) 的 \(f_0\) 的段以外的结构。
类似地,\(f_0=1+\min a\) 的情况几乎就是上述情况的翻版:忽略 \(p_1\) 的细节后,\(f_0=1+\min a\) 的区别就在于 \(a_x=\min a=f_0-1\) 的位置也是必须前缀最大值,这样的位置就对应了长度为 \(1\) 的段。
但是,但是,当我们重新讨论 \(f_0=1+\min a\) 的情况时,我们发现 \(p_1\) 对应的段如果为长度为 \(1\),则会出现相当多的例外。这是因为,\(p_1\) 之前没有任何元素,所以删除它后 \(p_2\) 一定是前缀最大值,而 \(a_1=f_0-1\),所以 \(p_2\) 必须是“必然前缀最大值”。于是,我们可以对于 \(p_1\) 对应长度为 \(1\) 的段的情况进行一个单独的计算。
将 \(f_0=\min a\) 和 \(f_0=1+\min a\) 合起来,就可以得到繁琐的讨论:
-
如果 \(p_1\) 对应的段长度 \(\ge 2\):
\[\sum_{t=1}^{f_0}\sum_{k\ge f_0-t}\binom{k+t-1}{t-1}[x^{n-2k}]\left[\frac{x^2}{1-x}\cdot \left(\frac{x^3}{1-x}+x\right)^{t-1}(1+x)^t\right] \] -
如果 \(p_1\) 对应的段长度为 \(1\),且 \(t=1\):
\[[n-1\ge 2(f_0-1)] \] -
如果 \(p_1\) 对应的段长度为 \(1\),且 \(1<t<f_0\),此时可以容斥计算:
\[\begin{aligned} &\sum_{t=2}^{f_0-1}\sum_{k\ge f_0-t}\binom{k+t-1}{t-1}[x^{n-2k}]\left[x\left(\frac{x^3}{1-x}+x\right)^{t-1}(1+x)^t\right]\\ -&\sum_{t=2}^{f_0-1}\sum_{k\ge f_0-t}\binom{k+t-2}{t-2}[x^{n-2k}]\left[x^2\left(\frac{x^3}{1-x}+x\right)^{t-1}(1+x)^{t-1}\right] \end{aligned} \] -
如果 \(p_1\) 对应的段长度为 \(1\),且 \(t=f_0\),此时可以直接计算:
\[\sum_{k\ge 0}\binom{k+f_0-2}{f_0-2}[x^{n-2k}]\left[x\left(\frac{x^3}{1-x}+x\right)^{t-1}(1+x)^{t-1}\right] \]
可以在 \(O(n^2)\) 的时间内预处理后面 GF 的系数。直接枚举看似是 \(O(n^3)\) 的,但是注意到 \(f_0\) 实际上不需要直接枚举,我们只需要由 \(t,k\) 确定 \(f_0\) 的个数就行,于是复杂度可以被优化到 \(O(n^2)\)。
顺便一说,上述分析并没有考虑 \(\min a\ge m\) 的条件。不过这并不复杂,对于 \(f_0>m\),用上面的方式计算即可;对于 \(f_0=m\),单独计算 \(f_0=\min a=m\) 的数量即可。
最后,处理 \(a\) 可能算重的历史遗留问题。考虑到直接计算都非常困难,我们还是倾向于证明“不会算重”。
证明思路并不复杂,用不等式导出矛盾即可,以下为详细过程:
Property.
不存在满足如下性质的 \(a\):
存在 \(f(p)=\min a\) 和 \(f(q)=1+\min a\) 的排列 \(p,q\),使得 \(a\) 可以由 \(p,q\) 构造。
假设存在。设 \(v=\min a\)。
考察 \(p\)。若 \(p_x\) 位置为 \(p\) 中前缀最大值,则 \(x<n\) 且 \(p_{x+1}\) 一定不是 \(p\) 中前缀最大值。
这一点可以导出 \(2v\le n\Rightarrow v\le \frac{n}{2}\)。
设 \(a\) 中有 \(\alpha\) 个 \(v\),\(\beta\) 个 \(v+1\)。容易发现,有 \(\alpha+\beta\le n\)。
此外,任意一个 \(a_x=v+1\) 的 \(x\) 必然类似地满足 \(p_x\) 为 \(p\) 中前缀最大值,\(x+2\le n\) 且 \(p_{x+1},p_{x+2}\) 一定不是 \(p\) 中前缀最大值。于是 \(a_{x+1}=a_{x+2}=v\),导出 \(2\beta\le \alpha\),接着可以导出 \(\beta\le \frac n 3\)。
最后,在 \(q\) 中,前缀最大值至少有 \(n-\beta\) 个,所以 \(v+1\ge n-\beta\),于是有 \(v\ge \frac 2 3n-1\)。
假如 \(\frac 2 3n-1\le \frac n 2\),可以解得 \(n\le 6\)。所以当 \(n>6\) 时,这样的 \(a\) 不存在;当 \(n\le 6\) 时,经过暴力验证也可以发现这样的 \(a\) 不存在。
于是这个恼人的问题就解决了。
代码
#include <cstdio>
#include <iostream>
#define rep( i, a, b ) for( int i = (a) ; i <= (b) ; i ++ )
#define per( i, a, b ) for( int i = (a) ; i >= (b) ; i -- )
const int mod = 1e9 + 7;
const int MAXN = 4e3 + 5;
template<typename _T>
inline void Read( _T &x ) {
x = 0; char s = getchar(); bool f = false;
while( ! ( '0' <= s && s <= '9' ) ) { f = s == '-', s = getchar(); }
while( '0' <= s && s <= '9' ) { x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar(); }
if( f ) x = -x;
}
template<typename _T>
inline void Write( _T x ) {
if( x < 0 ) putchar( '-' ), x = -x;
if( 9 < x ) Write( x / 10 );
putchar( x % 10 + '0' );
}
int poly[MAXN];
int coe1[MAXN][MAXN], coe2[MAXN][MAXN], coe3[MAXN][MAXN], coe4[MAXN][MAXN];
int C[MAXN][MAXN];
int N, M;
inline int Qkpow( int, int );
inline int Inv( const int &a ) { return Qkpow( a, mod - 2 ); }
inline int Mul( int x, const int &v ) { return 1ll * x * v % mod; }
inline int Sub( int x, const int &v ) { return ( x -= v ) < 0 ? x + mod : x; }
inline int Add( int x, const int &v ) { return ( x += v ) >= mod ? x - mod : x; }
inline int& MulEq( int &x, const int &v ) { return x = 1ll * x * v % mod; }
inline int& SubEq( int &x, const int &v ) { return ( x -= v ) < 0 ? ( x += mod ) : x; }
inline int& AddEq( int &x, const int &v ) { return ( x += v ) >= mod ? ( x -= mod ) : x; }
inline int Qkpow( int base, int indx ) {
int ret = 1;
while( indx ) {
if( indx & 1 ) MulEq( ret, base );
MulEq( base, base ), indx >>= 1;
}
return ret;
}
inline void Init( const int &n ) {
rep( i, 0, n ) {
C[i][0] = C[i][i] = 1;
rep( j, 1, i )
C[i][j] = Add( C[i - 1][j], C[i - 1][j - 1] );
}
poly[0] = 1;
rep( t, 1, n ) {
per( i, n, 1 ) AddEq( poly[i], poly[i - 1] ); // *= ( 1 + x )
rep( i, 0, n ) coe4[t][i] = poly[i];
rep( i, 1, n ) AddEq( poly[i], poly[i - 1] ); // *= 1 / ( 1 - x )
rep( i, 0, n ) coe1[t][i] = poly[i];
per( i, n, 0 ) {
int tmp = poly[i];
if( i >= 1 ) SubEq( tmp, poly[i - 1] );
if( i >= 2 ) AddEq( tmp, poly[i - 2] );
poly[i] = tmp;
} // *= x^2 - x + 1
rep( i, 0, n ) coe2[t][i] = poly[i];
}
rep( i, 0, n ) poly[i] = ( i == 0 );
rep( t, 1, n ) {
rep( i, 1, n ) AddEq( poly[i], poly[i - 1] );
per( i, n, 1 ) AddEq( poly[i], poly[i - 1] );
rep( i, 0, n ) coe3[t][i] = poly[i];
}
}
int main() {
// freopen( "beats.in", "r", stdin );
// freopen( "beats.out", "w", stdout );
Read( N ), Read( M ), Init( N );
int ans = 0;
for( int t = 1 ; t <= N ; t ++ ) {
for( int k = 0 ; N - 2 * k - t - 1 >= 0 ; k ++ ) {
int l = std :: max( t, M + 1 ), r = std :: min( t + k, N );
if( l <= r ) AddEq( ans, Mul( r - l + 1, Mul( C[k + t - 1][t - 1], coe1[t][N - 2 * k - t - 1] ) ) );
}
// if v == t
if( M + 1 <= t )
for( int k = 0 ; N - 2 * k - t >= 0 ; k ++ )
AddEq( ans, Mul( C[k + t - 2][t - 2], coe2[t - 1][N - 2 * k - t] ) );
// if 2 <= t < v
if( t >= 2 )
for( int k = 0 ; N - 2 * k - t >= 0 ; k ++ ) {
int res = 0;
AddEq( res, Mul( C[k + t - 1][t - 1], coe4[t][N - 2 * k - t] ) );
if( N - 2 * k - t - 1 >= 0 )
SubEq( res, Mul( C[k + t - 2][t - 2], coe2[t - 1][N - 2 * k - t - 1] ) );
int l = std :: max( t + 1, M + 1 ), r = std :: min( N, t + k );
if( l <= r ) AddEq( ans, Mul( res, r - l + 1 ) );
}
// if t == 1
if( t == 1 )
for( int v = M + 1 ; v <= N ; v ++ )
AddEq( ans, N - 1 >= 2 * ( v - t ) );
}
for( int t = 1 ; t <= M ; t ++ )
for( int k = M - t ; N - 2 * k - 3 * t + 1 >= 0 ; k ++ )
AddEq( ans, Mul( C[k + t - 1][t - 1], coe3[t][N - 2 * k - 3 * t + 1] ) );
Write( ans ), putchar( '\n' );
return 0;
}

浙公网安备 33010602011771号