• 线性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);
        
    
    }
  • 相关阅读:
    和菜鸟一起学产品之产品经理的自我管理能力
    和菜鸟一起学产品之产品经理的工作职责
    遗传算法解决TSP问题实现以及与最小生成树的对比
    双系统或三系统:Grub Rescue修复方法
    err:安装程序试图挂载映像 1(缺少ISO 9660图像)
    OpenCV手写数字字符识别(基于k近邻算法)
    最小生成树
    ubuntu12.04:Tomcat 7服务器:手动安装
    ubuntu12.04:jdk7:手动安装
    ubuntu12.04:Mysql数据库:手动安装
  • 原文地址:https://www.cnblogs.com/zsben991126/p/10813789.html
Copyright © 2020-2023  润新知