题解 ABC309Ex【Simple Path Counting Problem】

好好玩的题。

设普通生成函数 Fi,其中 [zk]Fi 表示从所有起点走到 (i,k) 的方案数。特别地,[zk]F1=aA[a=k]

注意到 Fi=(z1+1+z)Fi1 几乎成立,但是在 [z1]Fi[zM]Fi 处不成立。

尝试对 Fi 进行改造:

[zk]Fi={0,k=0k=M+1[zk]Fi,1kM[z2M+2k]Fi,M+2k2M+1

考察 Fi(z1+1+z) 的循环卷积(即 mod(z2M+21) 的结果),发现由于 Fi 是由 Fi 沿着 k=M+1 翻折并取相反数得到的,[z0]Fi[zM+1]Fi 永远会是 0,这就防止了我们移动到网格外,从而使得循环卷积结果的系数恰好是 Fi+1 的各项系数,即:

Fi+1Fi(z1+1+z)(mod(z2M+21))

使用快速幂即可,时间复杂度 O(MlogMlogN)

去掉封装的核心代码:(完整代码

Poly<mod, g> qmul(const Poly<mod, g>& a, const Poly<mod, g>& b) {
    Poly<mod, g> ans = a * b;
    int sz = (int)ans.size();
    rep(i, 2*m+2, sz-1) ans[i%(2*m+2)] += ans[i];
    ans.resize(2*m+2);
    return ans;
}

Poly<mod, g> qpow(Poly<mod, g> a, int k) {
    Poly<mod, g> ans{1};
    for(; k; k >>= 1, a = qmul(a, a)) if(k & 1) ans = qmul(ans, a);
    return ans;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    initPoly(N);
    cin >> n >> m >> k >> l;
    Poly<mod, g> a(2*m+2), b(2*m+2);
    rep(i, 1, k) {
        cin >> x;
        ++a[x];
        --a[2*m+2-x];
    }
    b[0] = b[1] = b[2*m+1] = 1;
    a = qmul(a, qpow(b, n-1));
    Modint<mod, g> ans = 0;
    rep(i, 1, l) {
        cin >> x;
        ans += a[x];
    }
    cout << ans << '\n';
    return 0;
}
posted @   rui_er  阅读(41)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示