首页 > 其他分享 >P8735

P8735

时间:2024-09-22 21:47:37浏览次数:1  
标签:sz int Res P8735 pts rep size

Statement

给出 \(k,p,L\),数序列 \(a\),满足如下条件:

  • \(1\le a_i\le k\)
  • \(\sum_i a_i=L\)
  • \(\nexists i,a_i\ge p\land a_{i+1}\ge p\)

答案对 \(20201114\) 取模,\(p\le k\le 1000, L\le 10^{18}\).

Solution

30 pts

注意到可以 dp,记 \(f(i,0/1)\) 为凑出 \(i\) 的方案数,其中最后一个数是否 \(<p\).

\[ \begin{aligned} f(i,1)&=\sum_{1\le j<p} f(i-j,1)+f(i-j,0)\\ f(i,0)&=\sum_{p\le j\le k} f(i-j,1)\\ f(0,1)&=1 \end{aligned} \]

答案为 \(f(L,0)+f(L,1)\),时间 \(O(kl)\),预计得分 30 pts.

我做了个没什么用的前缀和优化:记 \(g(i,0/1)\) 为 \(f(i,0/1)\) 的前缀和,推式子可得

\[ \begin{aligned} g(i,0)&=g(i-1,0)+g(i-p,1)-g(i-k-1,1)\\ g(i,1)&=2g(i-1,1)+g(i-1,0)-g(i-p,1)-g(i-p,0)\\ g(0,1)&=1 \end{aligned} \]

答案为 \(g(L,0)-g(L-1,0)+g(L,1)-g(L-1,1)\),时间 \(O(L)\),预计得分 30 pts.

60 pts

用矩阵快速幂优化上述 dp,\(f\) 或 \(g\) 都可以,时间 \(O(k^3\log L)\),带有 8 倍常数,预计得分 60 pts.

100 pts

考虑把 \(f(i,0)\) 拆成若干 \(f(i,1)\),这样就可以线性递推了!

不用写任意模数乘法,直接暴力乘就行,预处理系数也可以直接暴力,这是 \(O(k^2\log L)\) 的,期望 100 pts.

也可以用 \(g\) 算,把 \(g(i,0)\) 拆成若干 \(g(i,1)\) 就行了,预处理系数时会更优一点,需要稍微推一下式子。

你当然可以再写一个任意模数乘法做到 \(O(k\log k\log L)\)。

Code

#include <bits/stdc++.h>
using namespace std;
#define rep(i, j, k) for (int i = j; i <= k; ++i)
#define reo(i, j, k) for (int i = j; i >= k; --i)
typedef long long ll;
const int N = 2e5 + 10, P = 20201114;
int k, p, n, xishu[N], f[N][2];
ll L;

ll Mod(ll x) {
    return (x % P + P) % P;
}

struct Poly {
    vector<ll> f;
    ll & operator[] (int x) {
        return f[x];
    }
    Poly() {
        f.clear();
    }
    Poly operator* (Poly rhs) {
        Poly Res;
        int Slhs = f.size(), Srhs = rhs.f.size();
        Res.f.assign(Slhs + Srhs - 1, 0ll);
        rep(i, 0, Slhs - 1)
            rep(j, 0, Srhs - 1)
                (Res[i + j] += f[i] * rhs[j] % P) %= P;
        return Res;
    }
    void Modulo() {
        int sz = f.size();
        if (sz < p + k) {
            return;
        }
        reo(i, sz - 1, p + k - 1) {
            ll x = f[i];
            if (x) {
                rep(j, 1, p + k - 1) {
                    (f[i - j] += x * xishu[j] % P) %= P;
                }
                f[i] = 0;
            }
        }
        f.resize(p + k);
    }

    void print() {
        for (auto v : f) cout << v << ' ';
        cout << '\n';
    }
} base, Res;

int main() {
    // freopen("jump.in", "r", stdin), freopen("jump.out", "w", stdout);
    ios::sync_with_stdio(false), cin.tie(nullptr);
    cin >> k >> p >> L;
    f[0][1] = 1;
    rep(i, 1, k + p) {
        rep(j, 1, p - 1) {
            if (i - j >= 0) (f[i][1] += f[i - j][1] + f[i - j][0]) %= P;
            else break;
        }
        rep(j, p, k) {
            if (i - j >= 0) (f[i][0] += f[i - j][1]) %= P;
            else break;
        }
    }
    rep(i, 1, p - 1) {
        ++xishu[i];
        rep(j, p, k) {
            ++xishu[i + j];
        }
    }
    if (L <= k) {
        ll res = f[L][1];
        rep(i, L - k, L - p) {
            if (i >= 0) (res += f[i][1]) %= P;
            else break;
        }
        cout << res << '\n';
        return 0;
    }
    ll res = 0, Target = L - k - 1;
    base.f.assign(2, 0ll), base[1] = 1;
    Res.f.assign(1, 0ll), Res[0] = 1;
    for (; Target; Target >>= 1, base = base * base, base.Modulo()) {
        if (Target & 1) Res = Res * base, Res.Modulo();
    }
    rep(i, 0, k + p - 1) {
        if (i >= (int)Res.f.size()) break;
        (res += Res[i] * f[i + 1][1] % P) %= P;
    }
    rep(i, 1, k - p) {
        int sz = Res.f.size() + 1;
        Res.f.resize(sz);
        reo(i, sz, 1) Res[i] = Res[i - 1];
        Res[0] = 0;
        Res.Modulo();
        rep(i, 0, k + p - 1) {
            if (i >= (int)Res.f.size()) break;
            (res += Res[i] * f[i + 1][1] % P) %= P;
        }
    }
    rep(i, 1, p) {
        int sz = Res.f.size() + 1;
        Res.f.resize(sz);
        reo(i, sz, 1) Res[i] = Res[i - 1];
        Res[0] = 0;
        Res.Modulo();
    }
    rep(i, 0, k + p - 1) {
        if (i >= (int)Res.f.size()) break;
        (res += Res[i] * f[i + 1][1] % P) %= P;
    }
    cout << Mod(res) << '\n';
    return 0;
}

标签:sz,int,Res,P8735,pts,rep,size
From: https://www.cnblogs.com/laijinyi/p/18425955

相关文章

  • P8735 蓝跳跳 题解
    Statement给出\(k,p,L\),数序列\(a\),满足如下条件:\(1\lea_i\lek\)\(\sum_ia_i=L\)\(\nexistsi,a_i\gep\landa_{i+1}\gep\)答案对\(20201114\)取模,\(p\lek\le1000,L\le10^{18}\).Solution30pts注意到可以dp,记\(f(i,0/1)\)为凑出\(i\)的方案......