标签:mes splay exp 表示 blog article csdn 相关 两种
校内赛的改编题目,题意基本与[HDU6848]Expectation相同。
首先,不难发现,本题就是求所有不同的操作序列的距离和,最后乘上 \(\frac{1}{n!2^n}\) 的概率就是答案。
于是考虑如何求这个距离和。这里有两种方法:
本题的贡献显然是可以拆分的。我们只需要计算 \(x_{i+1}-x_i\) 会被算几次就好了。
显然每一段的次数仅与数量 \(n\) 和段数 \(i\) 相关,因此可以定义状态:
\(f(n,i)\) :有 \(n\) 球 \(n+1\) 洞时,\(x_{i+1}-x_i\) 的计算次数。
先画出示意图如下,我们考虑求第 \(3\) 段的次数。
o o o
U U U U
|--|--|--|--|--|--|
1 2 3 4 5 6
其中 o
表示球,U
表示洞。下方标注了每一段。
那么我们随便让一个球进洞:
o o o
/
U U U U
|--|--|--|--|--|--|
1 2 3 4 5 6
--------Then-------
o o
U U U
|--|--------|--|--|
1 2 3 4
可以发现,现在球和洞各减少了一个,并且原先的第 \(3\) 段现在被包在了第 \(2\) 段里面。因此这样的话会转移到 \(f(n-1,i-1)\) ,仅有一种情况。
再考虑剩下两种情况:
o o o
U U U U
|--|--|--|--|--|--|
1 2 3 4 5 6
--------Then-------
o o
U U U
|--------|--|--|--|
1 2 3 4
现在它转移到了 \(f(n-1,i-2)\) 里面,对应了 \(i-1\) 种转移的情况。
o o o
/
U U U U
|--|--|--|--|--|--|
1 2 3 4 5 6
--------Then-------
o o
U U U
|--|--|--|--------|
1 2 3 4
现在它转移到了 \(f(n-1,i)\) 里面,对应了 \(2n-i\) 种转移的情况。
接着考虑当前这一步带来的次数。当我们将 \(i+1\) 移到 \(i\) 里面(或者 \(i\) 移到 \(i+1\) 里面)的时候,我们就会带来 1 次的贡献,总共就会带来 \((i-1)!\times 2^{i-1}\) 的贡献。
因此可以得到转移:
于是这个就可以 \(O(n^2)\) 预处理了。最后每次 \(O(n)\) 扫一遍就可以计算答案了。
该方法仅针对改编后的题目,仅可以通过一次询问的情况。
方案 2.1:请参考 zxy 巨佬的博客。
方案 2.2:
这是本人口胡的做法,并且还没有优化出来
可以发现,最后只有一个洞会留下来。我们可以枚举这个洞,这样左右两边就是独立的,且洞数恰好等于球数。
因此可以定义 \(f(i,j)\) 表示区间 \([i,j]\) 被消完的操作序列的距离和,且 \(i\) 与 \(j\) 的奇偶性不同。
以 \(i\) 偶 \(j\) 奇的转移为例。我们可以枚举 \(i\) 进的洞 \(k\) ,那么 \((i+1,k-1)\) 必须在 \(i\) 被操作之前被消完。而 \((k+1,j)\) 的操作则任意。可以发现我们得到了两个子问题。
注意到合法序列的数量仅与区间长度有关。因此设 \(g(i)\) 表示长度为 \(i\) 的区间的合法操作序列的个数。令 \(L\) 为 \([i,j]\) 中球的个数, \(l\) 为 \([i,k]\) 中球的个数。可以得到转移:
由于是统计序列,所以需要乘上组合数计算序列的形态。
这样转移是 \(O(n^3)\) 的,如果有会优化的请一定要告诉我。
小结:
方法 1 的关键在于拆分贡献独立计算和提取影响状态的信息。
方法 2 ,作为一个未通过的做法......
#include <cstdio>
typedef long long LL;
const int mod = 998244353;
const int MAXN = 3005;
template<typename _T>
void read( _T &x )
{
x = 0; char s = getchar(); int f = 1;
while( s < ‘0‘ || ‘9‘ < s ) { f = 1; if( s == ‘-‘ ) f = -1; s = getchar(); }
while( ‘0‘ <= s && s <= ‘9‘ ) { x = ( x << 3 ) + ( x << 1 ) + ( s - ‘0‘ ); s = getchar(); }
x *= f;
}
template<typename _T>
void write( _T x )
{
if( x < 0 ) putchar( ‘-‘ ), x = -x;
if( 9 < x ) write( x / 10 );
putchar( x % 10 + ‘0‘ );
}
int f[MAXN][MAXN << 1];
int X[MAXN];
int N, inv;
int Qkpow( int, int );
int Inv( const int a ) { return Qkpow( a, mod - 2 ); }
int Sub( int x, int v ) { return x < v ? x + mod - v : x - v; }
int Mul( LL x, int v ) { x *= v; if( x >= mod ) x %= mod; return x; }
int Add( int x, int v ) { return x + v >= mod ? x + v - mod : x + v; }
int Fix( const int a ) { return ( a % mod + mod ) % mod; }
int Qkpow( int base, int indx )
{
int ret = 1;
while( indx )
{
if( indx & 1 ) ret = Mul( ret, base );
base = Mul( base, base ), indx >>= 1;
}
return ret;
}
void Init( const int n )
{
int coe = 1;
f[1][1] = f[1][2] = 1;
for( int i = 2 ; i <= n ; i ++ )
{
coe = Mul( 2 * ( i - 1 ), coe );
for( int j = 1 ; j <= 2 * i ; j ++ )
{
f[i][j] = Add( f[i - 1][j - 1], Mul( f[i - 1][j], 2 * i - j ) );
if( j >= 2 ) f[i][j] = Add( f[i][j], Mul( f[i - 1][j - 2], j - 1 ) );
f[i][j] = Add( f[i][j], coe );
}
}
inv = Inv( Mul( coe, 2 * n ) );
}
int main()
{
read( N ), Init( N );
for( int i = 1 ; i <= 2 * N + 1 ; i ++ ) read( X[i] );
int ans = 0;
for( int i = 1 ; i <= N ; i ++ )
ans = Add( ans, Add( Mul( Fix( X[i << 1] - X[( i << 1 ) - 1] ), f[N][( i << 1 ) - 1] ),
Mul( Fix( X[( i << 1 ) + 1] - X[i << 1] ), f[N][i << 1] ) ) );
write( Mul( ans, inv ) ), putchar( ‘\n‘ );
return 0;
}
标签:mes splay exp 表示 blog article csdn 相关 两种
原文地址:https://www.cnblogs.com/crashed/p/13777006.html