AcWing
  • 首页
  • 课程
  • 题库
  • 更多
    • 竞赛
    • 题解
    • 分享
    • 问答
    • 应用
    • 校园
  • 关闭
    历史记录
    清除记录
    猜你想搜
    AcWing热点
  • App
  • 登录/注册

AtCoder abc 213. H - Stroll    原题链接    简单

作者: 作者的头像   Union_Find ,  2025-06-10 16:37:26 · 福建 ,  所有人可见 ,  阅读 4


1


题意

洛谷的翻译太直接的吧。

有一个 $n$ 个点 $m$ 条边的图,第 $i$ 条边有 $p_{i,j}$ 条长度为 $j$ 的路。现在从 $1$ 点出发,求走长度恰好为 $T$ 的路径后回到 $1$ 的方案数。

模 $998244353$。

$1 \le n,m \le 10,1 \le T \le 4 \times 10^4$。

分析

这题 $n,m$ 很小,我们考虑可以 dp。设 $f_{i,j}$ 表示走到点 $i$,走了 $j$ 的长度的方案数。初始状态 $f_{1,0} = 1$。

考虑转移。

$$f_{u,i} = \sum_{E_k = (u,v)} \sum_{j=0}^{i-1} f_{v,j}p_{k,i-j}$$

这个式子长得异常清秀,发现这个式子就是 分治 FFT 的式子。暴力做是 $O(mT^2)$ 的。考虑优化。

我们按照分治 FFT 的做法做,时间复杂度可以做到 $O(mT\log^2T)$,这个是容易的,按照板子做即可。

#include <bits/stdc++.h>
using namespace std;
#define il inline
#define poly vector <int>
il int rd(){
    int s = 0, w = 1;
    char ch = getchar();
    for (;ch < '0' || ch > '9'; ch = getchar()) if (ch == '-') w = -1;
    for (;ch >= '0' && ch <= '9'; ch = getchar()) s = ((s << 1) + (s << 3) + ch - '0');
    return s * w;
}
const int N = (1 << 20) + 5;
namespace Poly{
    int rev[N];
    const int P = 998244353, G = 3, invG = 332748118;
    il int ksm(int x, int r){
        int ans = 1;
        for (; r; x = 1ll * x * x % P, r >>= 1) if (r & 1) ans = 1ll * ans * x % P;
        return ans;
    }
    il poly get(int n){return poly(n + 1);}
    il void NTT (poly &a, int n, int typ){
        for (int i = 0; i < n; i++) if (i < rev[i]) swap(a[i], a[rev[i]]);
        for (int len = 1; len < n; len <<= 1){
            int wn = ksm(typ == 1 ? G : invG, (P - 1) / (len << 1));
            for (int i = 0; i < n; i += (len << 1)){
                int w = 1;
                for (int j = 0; j < len; j++){
                    int x = a[i + j], y = 1ll * w * a[i + j + len] % P;
                    a[i + j] = (x + y) % P, a[i + j + len] = (x - y + P) % P, w = 1ll * w * wn % P;
                }
            }
        }
        if (typ == -1){
            int inv = ksm(n, P - 2);
            for (int i = 0; i < n; i++) a[i] = 1ll * a[i] * inv % P;
        }
    }
    il poly mod(poly a, int n){a.resize(n, 0);return a;}
    il poly operator *(poly a, poly b){
        int n = a.size() - 1, m = b.size() - 1, L = 1;
        while (L <= n + m) L <<= 1;
        a.resize(L), b.resize(L);
        for (int i = 0; i < L; i++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) ? (L >> 1) : 0);
        NTT(a, L, 1), NTT(b, L, 1);
        int inv = ksm(L, P - 2);
        for (int i = 0; i < L; i++) a[i] = 1ll * a[i] * b[i] % P;
        NTT(a, L, -1);
        return mod(a, n + m + 1);
    }
};
using namespace Poly;
int n, m, T, tu[15], tv[15];
poly f[15], p[15], h, t;
void solve(int l, int r){
    if (l == r) return ;
    int mid = (l + r) >> 1;
    solve(l, mid);
    for (int i = 1; i <= m; i++){
        int u = tu[i], v = tv[i];
        h = get(mid - l), t = get(r - l);
        for (int j = l; j <= mid; j++) h[j - l] = f[v][j];
        for (int j = 0; j <= r - l; j++) t[j] = p[i][j];
        h = h * t;
        for (int j = mid + 1; j <= r; j++) f[u][j] = (f[u][j] + h[j - l]) % P;
        swap(u, v);
        h = get(mid - l), t = get(r - l);
        for (int j = l; j <= mid; j++) h[j - l] = f[v][j];
        for (int j = 0; j <= r - l; j++) t[j] = p[i][j];
        h = h * t;
        for (int j = mid + 1; j <= r; j++) f[u][j] = (f[u][j] + h[j - l]) % P;
    }
    solve(mid + 1, r);
}
signed main(){
    n = rd(), m = rd(), T = rd();
    for (int i = 1; i <= m; i++){
        tu[i] = rd(), tv[i] = rd(), p[i] = get(T);
        for (int j = 1; j <= T; j++) p[i][j] = rd();
    }
    for (int i = 1; i <= n; i++) f[i] = get(T);
    f[1][0] = 1;
    solve(0, T);
    printf ("%d\n", f[1][T]);
    return 0;
}

0 评论

App 内打开
你确定删除吗?
1024
x

© 2018-2025 AcWing 版权所有  |  京ICP备2021015969号-2
用户协议  |  隐私政策  |  常见问题  |  联系我们
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标 qq图标
请输入绑定的邮箱地址
请输入注册信息