ACM3759 二维跑步 题解

题目分析

这道题是二维空间上的随机游走。基本思路是:

  1. 观察转移规则,发现从任意 出发,向右/原地/向左的选择数都是 ,与 无关
  2. 由此直接写出总量的生成函数
  3. 转化为普通多项式后用三项递推 求出所有系数

最终复杂度

数学分析

为走 步后落在 处的总方案数( 任意)。观察题目给出的转移规则:

当前位置 向右 原地 向左
到全部 3 个 保持 (2 种)
到全部 3 个 保持 (2 种)
到全部 3 个 保持 (2 种)

关键观察:无论当前在哪个 ,向右走都有 3 种选择,原地有 1 种,向左有 2 种。因此 的递推与 无关:

定义生成函数 ,上式等价于:

初始 (只有 ),故:

问题转化为:求 的系数之和。

化为普通多项式

。则:

位置 的方案数恰好是 。答案即为:

三项递推式

。对两边求导:

两边同乘

,以及 代入,比较 的系数:

整理得:

初始条件

  • (所有因子都取常数项
  • (多项式无负次项)
  • 时:

由这三项递推式,可以 一次性算出全部 ,无需任何迭代 DP。

代码

#include <iostream>
#include <vector>
using namespace std;

const int MOD = 998244353;

int mod_pow(int base, int exp)
{
    int result = 1;
    while (exp) {
        if (exp & 1) result = (long long)result * base % MOD;
        base = (long long)base * base % MOD;
        exp >>= 1;
    }
    return result;
}

void precompute_inverses(int n, vector<int> &inv)
{
    inv[1] = 1;
    for (int i = 2; i <= n; ++i)
        inv[i] = (long long)(MOD - MOD / i) * inv[MOD % i] % MOD;
}

vector<int> compute_coefficients(int n, const vector<int> &inv)
{
    vector<int> c(2 * n + 1, 0);

    c[0] = mod_pow(2, n);

    if (n == 0) return c;

    c[1] = (long long)n * c[0] % MOD * inv[2] % MOD;

    for (int j = 1; j < 2 * n; ++j) {
        int term1 = (long long)(6LL * n - 3LL * j + 3) * c[j - 1] % MOD;
        int term2 = (long long)(n - j) * c[j] % MOD;
        int numerator = (term1 + term2) % MOD;
        if (numerator < 0) numerator += MOD;
        c[j + 1] = (long long)numerator * inv[2 * (j + 1)] % MOD;
    }

    return c;
}

int compute_answer(const vector<int> &c, int n, int m)
{
    int ans = 0;
    int lo = max(0, n - m);
    int hi = min(2 * n, n + m);
    for (int j = lo; j <= hi; ++j)
        ans = (ans + c[j]) % MOD;
    return ans;
}

int main()
{
    int n, m;
    cin >> n >> m;

    vector<int> inv(4 * n + 2);
    precompute_inverses(4 * n + 1, inv);

    vector<int> c = compute_coefficients(n, inv);
    cout << compute_answer(c, n, m) << endl;

    return 0;
}

复杂度分析

步骤 时间 空间
预处理逆元
递推求
区间求和
总计
  • 递推式每步只需两次乘法、一次加法、一次除法(乘逆元),常数极小
  • 所需的模逆元 inv[1..4n] 可以 线性预处理
  • 相比于迭代 DP 的 ,此方法可以直接处理 高达 级别的数据