CF1152 F. Neko Rules the Catniverse (dp)

题意

一条长为 \(n\) 的数轴,能够从任意整点 \(\in [1, n]\) 出发,假设当前在 \(x\) ,下一步能到达的点 \(y\) 须要知足,\(y\) 从未到过,且 \(1 \le y \le x + m\) ,问长刚好为 \(k\) 的合法路径条数。c++

数据范围

对于 \(F1\)\(1 \le n \le 10^5, 1 \le k \le \min(n, 12), 1 \le m \le 4\)git

对于 \(F2​\)\(1 \le n \le 10^9​\)优化

题解

比较 \(\text{tricky}\) 的一个题。ui

考虑咱们当前假设通过的路径为 \(v_1, v_2, \cdots, v_p\) ,咱们当前能够添加一个 \(x < \min_{i = 1}^{p} \{v_i\}\) 。显然咱们是必定能够添加到队尾的,其次咱们能够添加到那些 \(v_i \le x + m\) 的前面。spa

那么咱们就获得一个很显然的 \(dp\) 了,考虑从大到小依次考虑每一个数填仍是不填就能轻松转移了。debug

具体来讲设 \(dp[i][j][sta]\) 为当前在第 \(i\) 个位置,路径长度为 \(j\) ,最后 \(m\) 个位置状压后的状态为 \(sta\)code

每次转移的时候,若是不填直接转过去,填的话能够转到后 \(m\) 个有 \(1\) 的状态以及队尾,也就是 \(1 + bitcount(sta)\)get

这样 \(dp\) 恰好每条路都能一一对应上。it

对于 \(F1\) 直接 \(\mathcal O(nk2^m)\) 就好了,\(F2\) 考虑利用矩阵快速幂优化到 \(\mathcal O((k2^m)^3 \log n)\) 。(说实话 \(F2\) 没啥意思。。)class

代码

#include <bits/stdc++.h>

#define For(i, l, r) for (register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for (register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Rep(i, r) for (register int i = (0), i##end = (int)(r); i < i##end; ++i)
#define Set(a, v) memset(a, v, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define debug(x) cout << #x << ": " << (x) << endl

using namespace std;

template<typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, T b) { return b > a ? a = b, 1 : 0; }

inline int read() {
    int x(0), sgn(1); char ch(getchar());
    for (; !isdigit(ch); ch = getchar()) if (ch == '-') sgn = -1;
    for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48);
    return x * sgn;
}

void File() {
#ifdef zjp_shadow
    freopen ("F1.in", "r", stdin);
    freopen ("F1.out", "w", stdout);
#endif
}

const int N = 1e5 + 1e3, K = 14, M = 4, Mod = 1e9 + 7;

int dp[N][K][1 << M];

int main() {

    File();

    int n = read(), k = read(), m = read();

    dp[0][0][0] = 1;
    Rep (i, n) For (j, 0, k) Rep (sta, 1 << m) {
        (dp[i + 1][j][sta >> 1] += dp[i][j][sta])%= Mod;
        int res = dp[i][j][sta] * (1ll + __builtin_popcount(sta)) % Mod;
        (dp[i + 1][j + 1][(sta >> 1) | (1 << m - 1)] += res) %= Mod;
    }

    int ans = 0;
    Rep (sta, 1 << m)
        (ans += dp[n][k][sta]) %= Mod;
    printf ("%d\n", ans);

    return 0;

}
相关文章
相关标签/搜索