题意关键点合法按键序列:按x后x锁死,小于x全部解锁;只有按更大按钮,x才能重按。
每按完按钮:停下 / 走单向边。
初始:s且已按(b_s);要求:停在t、最后按键(b_t),求方案数。核心思想(官方 DP,不用矩阵求逆)把序列按全局最大值r拆分:前缀(<r) + 按r + 后缀(<r)
(g[r]):走到准备按r(按r之前)
(f[r]):按完r之后往后走
总方案:(dp[i][j]=\sum g[r][i]\times f[r][j])
数组 flag:
flag=0:全局预处理,无查询约束;flag=1:带当前查询((b_s,s,b_t,t))约束
(dp[x][y][u][v][c]):(x=1)绑定起点,(y=1)绑定终点;最多允许按钮c,(u\to v)方案。
normal () 预处理 flag=0
(dp[0][0][][][c])先继承(c-1)(最大值(<c))
更新(g_0,f_0):可直接原地按按钮;也可走边接上(c-1)子序列
累加最大值恰好为r的贡献:(dp += \sum g_0[r]\times f_0[r])
calc () 回答一组查询
清空 flag=1 的数组,保留 flag=0 预处理结果
从小到大枚举c;特殊基点:(c=b_s)初始化(g_1),(c=b_t)初始化(f_1)
(dp_{10}):绑起点;(dp_{01}):绑终点;(dp_{11}):同时绑起点终点,答案就是(dp[1][1][s][t][k])
(dp_{10} += g_1[r]\times f_0[r])
(dp_{01} += g_0[r]\times f_1[r])
(dp_{11} += g_1[r]\times f_1[r])
代码缺陷
memset(dp[i][j],0,...)条件if(i+j)错误,漏掉dp[0][0]清零(但dp[0][0]是预处理好的,本就不该清,这点没问题;但其他 memset 范围不全)
原代码不能直接 AC 样例,memset 只覆盖部分内存,部分残留脏数据。
复杂度(O(K(N3+N2))),(N,K\le60)。
对比矩阵求逆写法:矩阵版所有查询共用预处理,(O(KN^3));这份 DP 每个查询要跑一遍 calc,(O(Q\cdot K N^2))。