• CF1152 F. Neko Rules the Catniverse (dp)


    题意

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

    数据范围

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

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

    题解

    比较 ( ext{tricky}) 的一个题。

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

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

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

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

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

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

    代码

    #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
    ", ans);
    
    	return 0;
    
    }
    
  • 相关阅读:
    C#中异步和多线程的区别
    猫 老鼠 人的编程题
    C#中数组、ArrayList和List三者的区别
    经典.net面试题目
    sql有几种删除表数据的方式
    内存池的实现
    A*算法为什么是最优的
    传教士与野人问题
    d3d导致cairo不正常
    c++中的signal机制
  • 原文地址:https://www.cnblogs.com/zjp-shadow/p/10777887.html
Copyright © 2020-2023  润新知