• 线性dp——求01串最大连续个数不超过k的方案数,cf1027E 好题!


    只写了和dp有关的。。博客 https://www.cnblogs.com/huyufeifei/p/10351068.html

    关于状态的继承和转移

    这题的状态转移要分开两步来做:

      1.继承之前状态的合法构造数量

      2.构造出该状态下特有的新构造数量

    这类dp尽量由已知状态推出未知态(加法转移)来做。。。自己用减法转移都不知道边界怎么写。。

    #include <cstdio>
    #include <algorithm>
    
    const int N = 510, MO = 998244353;
    
    int f[N][N][2], sum[N];
    
    inline void add(int &a, const int &b) {
        a = (a + b) % MO;
        return;
    }
    
    int main() {
        int n, k;
        scanf("%d%d", &n, &k);
        for(int j = 1; j <= n; j++) {
            f[0][j][0] = 1;
        }
        for(int i = 0; i <= n; i++) {
            for(int j = 1; j <= n; j++) {
                // f[i][j][0/1]继承前状态
                for(int k = 1; k < j && i + k <= n; k++) {
                    add(f[i + k][j][0], f[i][j][0]);
                    add(f[i + k][j][1], f[i][j][1]);
                }
                if(i + j <= n) {//构造出新的方案
                    add(f[i + j][j][1], f[i][j][0]);
                    add(f[i + j][j][1], f[i][j][1]);
                }
            }
        }
        
        for(int i = 1; i <= n; i++)printf("%d ", f[n][i][1]);
        long long ans = 0LL;
        for(int i = 1; i <= n; i++)
            for(int j = 1; (long long)j * i < k && j <= n; j++)
                ans = (ans + f[n][i][1] * f[n][j][1] % MO) % MO;
        ans = ans * 2 % MO;
        printf("%lld
    ", ans);
    }

     更新:可以把dp[i][j]转换成前缀和来做,最后相减一下就变成了上面的那种dp[i][j]表示的状态

    相比上一中感觉更加直观好写,即对于每种状态,枚举k个连续的1放在末尾,然后把对应的之前的状态加上去就可以了

    #include <cstdio>
    #include <cstring>
    using namespace std;
    typedef long long ll;
    
    const int N = 505;
    const ll P = 998244353LL;
    
    int n, siz;
    ll f[N][N];
    
    inline int min(int x, int y) {
        return x > y ? y : x;
    }
    
    int main() {
        scanf("%d%d", &n, &siz);
        
        f[0][0] = 1LL;
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= i; j++)
                for(int k = 1; k <= j; k++)
                    f[i][j] = (f[i][j] + f[i - k][min(j, i - k)]) % P;
        for(int i = n; i >= 1; i--)
            f[n][i] = (f[n][i] - f[n][i - 1] % P + P) % P;
            
    //for(int i = 1; i <= n; i++)printf("%lld ", f[n][i]);  
        ll ans = 0LL;
        for(int i = 1; i <= n; i++)
            for(int j = 1; j * i < siz && j <= n; j++)
                ans = (ans + f[n][i] * f[n][j] % P) % P;
        ans = ans * 2 % P;
        printf("%lld
    ", ans);
        
    
    }
  • 相关阅读:
    flink checkpoint机制的实现
    openjdk源码分析之AtomicLong
    cpp之宏和函数调用约定
    JNA 相关问题
    spark RDD
    最长连续序列
    买卖股票的最佳时机
    二叉树展开为链表
    不同的二叉搜索树
    柱状图中最大的矩形
  • 原文地址:https://www.cnblogs.com/zsben991126/p/10813789.html
Copyright © 2020-2023  润新知