Solution -「多校联训」轮回
有 个黑盒,第 个黑盒可以让输入变量以 的概率保持不变,以 的概率加一或减一。称一次从 开始的游戏为:初始变量的值为 ,从 开始,将变量依次输入 ,直到变量的绝对值大于 。处理 次操作:
- 求此时一次从某个 开始的游戏期望经过多少个黑盒。答案模 ;
- 修改某个 的值。
,。
DP 是平凡的:令 表示绝对值为 的变量将要输入第 个黑盒时,期望还能经过多少黑盒。那么
紧接着,你看我久违地把 DP 状态写成下标的形式就知道,应用整体思想,令
据此不难得出
其中 是一个仅与 有关的转移矩阵。鉴于答案要求 ,我们只需要关心某个特定的 的值。从方程角度考虑,发现
所以说用线段树维护 的区间积,快速求出 中的 ,然后 消元就行。最终最劣复杂度为 。
/* Clearink */
#include <cstdio>
#include <cassert>
#include <cstring>
#include <iostream>
#define rep( i, l, r ) for ( int i = l, rep##i = r; i <= rep##i; ++i )
#define per( i, r, l ) for ( int i = r, per##i = l; i >= per##i; --i )
inline int rint() {
int x = 0, f = 1, s = getchar();
for ( ; s < '0' || '9' < s; s = getchar() ) f = s == '-' ? -f : f;
for ( ; '0' <= s && s <= '9'; s = getchar() ) x = x * 10 + ( s ^ '0' );
return x * f;
}
template<typename Tp>
inline void wint( Tp x ) {
if ( x < 0 ) putchar( '-' ), x = -x;
if ( 9 < x ) wint( x / 10 );
putchar( x % 10 ^ '0' );
}
const int MAXN = 1e5, MAXK = 5, MOD = 1e9 + 7, INV2 = MOD + 1 >> 1;
int n, m /* i.e. k */, q;
inline int mul( const long long a, const int b ) { return a * b % MOD; }
inline int sub( int a, const int b ) { return ( a -= b ) < 0 ? a + MOD : a; }
inline void subeq( int& a, const int b ) { ( a -= b ) < 0 && ( a += MOD ); }
inline int add( int a, const int b ) { return ( a += b ) < MOD ? a : a - MOD; }
inline void addeq( int& a, const int b ) { ( a += b ) >= MOD && ( a -= MOD ); }
inline int mpow( int a, int b ) {
int ret = 1;
for ( ; b; a = mul( a, a ), b >>= 1 ) ret = mul( ret, b & 1 ? a : 1 );
return ret;
}
struct Matrix {
static const int MAXS = MAXK + 1;
int mat[MAXS + 1][MAXS + 1];
Matrix(): mat{} {} // !!!
inline int* operator [] ( const int k ) { return mat[k]; }
friend inline Matrix operator * ( const Matrix& u, const Matrix& v ) {
Matrix ret;
rep ( i, 0, MAXS ) rep ( k, 0, MAXS ) rep ( j, 0, MAXS ) {
addeq( ret[i][j], mul( u.mat[i][k], v.mat[k][j] ) );
}
return ret;
}
};
inline void setTMat( Matrix& u, const int p ) {
u = Matrix();
u[0][0] = p;
rep ( i, 0, m + 1 ) u[m + 1][i] = 0, u[i][m + 1] = 1;
if ( !m ) return ;
u[0][1] = sub( 1, p );
int cp = mul( INV2, sub( 1, p ) );
rep ( i, 1, m ) {
u[i][i] = p, u[i][i - 1] = cp;
if ( i + 1 <= m ) u[i][i + 1] = cp;
}
}
struct SegmentTree {
Matrix sum[MAXN << 2];
inline void build( const int u, const int l, const int r ) {
if ( l == r ) {
int a = rint();
setTMat( sum[u], mul( a, mpow( rint(), MOD - 2 ) ) );
return ;
}
int mid = l + r >> 1;
build( u << 1, l, mid ), build( u << 1 | 1, mid + 1, r );
sum[u] = sum[u << 1] * sum[u << 1 | 1];
}
inline void modify( const int u, const int l, const int r,
const int x, const int p ) {
if ( l == r ) return setTMat( sum[u], p );
int mid = l + r >> 1;
if ( x <= mid ) modify( u << 1, l, mid, x, p );
else modify( u << 1 | 1, mid + 1, r, x, p );
sum[u] = sum[u << 1] * sum[u << 1 | 1];
}
inline Matrix query( const int u, const int l, const int r,
const int ql, const int qr ) {
if ( ql <= l && r <= qr ) return sum[u];
int mid = l + r >> 1;
if ( qr <= mid ) return query( u << 1, l, mid, ql, qr );
if ( mid < ql ) return query( u << 1 | 1, mid + 1, r, ql, qr );
return query( u << 1, l, mid, ql, qr )
* query( u << 1 | 1, mid + 1, r, ql, qr );
}
} sgt;
inline void gauss( const int s, int a[MAXK + 1][MAXK + 2], int* x ) {
rep ( i, 0, s ) {
int p;
rep ( j, i, s ) if ( a[j][i] ) { p = j; break; }
if ( i != p ) std::swap( a[i], a[p] );
assert( a[i][i] );
int iv = mpow( a[i][i], MOD - 2 );
rep ( j, i + 1, s ) {
int t = mul( a[j][i], iv );
rep ( k, i, s + 1 ) subeq( a[j][k], mul( t, a[i][k] ) );
}
}
per ( i, s, 0 ) {
x[i] = mul( a[i][s + 1], mpow( a[i][i], MOD - 2 ) );
per ( j, i - 1, 0 ) subeq( a[j][s + 1], mul( x[i], a[j][i] ) );
}
}
inline int solve( Matrix& u ) {
int a[MAXK + 1][MAXK + 2], x[MAXK + 1];
memset( a, 0, sizeof a );
rep ( i, 0, m ) {
a[i][i] = MOD - 1;
rep ( j, 0, m ) addeq( a[i][j], u[i][j] );
a[i][m + 1] = sub( 0, u[i][m + 1] );
}
gauss( m, a, x );
return x[0];
}
int main() {
freopen( "samsara.in", "r", stdin );
freopen( "samsara.out", "w", stdout );
n = rint(), m = rint(), q = rint();
sgt.build( 1, 1, n );
for ( int op, i, a, b; q--; ) {
op = rint(), i = rint();
if ( op == 1 ) {
Matrix tmat;
if ( i == 1 ) tmat = sgt.query( 1, 1, n, 1, n );
else {
tmat = sgt.query( 1, 1, n, i, n )
* sgt.query( 1, 1, n, 1, i - 1 );
}
wint( solve( tmat ) ), putchar( '\n' );
} else {
a = rint(), b = rint();
sgt.modify( 1, 1, n, i, mul( a, mpow( b, MOD - 2 ) ) );
}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现