• P5664 [CSP-S2019] Emiya 家今天的饭


    很久之前的题今天才做。

    Solution

    发现每种主要食材不能超过(leftlfloor frac{k}{2} ight floor),那考虑不合法的情况,有也仅有一种主要食材会出现(> leftlfloor frac{k}{2} ight floor)的情况。
    于是,我们考虑如何求出总情况数和不合法情况数,然后再相减就是答案。
    考虑枚举不合法的主要食材(col)。设(dp[i][j][k])为考虑前(i)种烹饪方法,用第(i)种烹饪方法第(col)种主要食材做了(j)道菜,用(i)种烹饪方法做除第(col)种主要食材其他的菜做了(k)道。则

    [dp[i][j][k] = dp[i - 1][j][k] + dp[i - 1][j - 1][k] cdot a[i][col] + dp[i - 1][j][k - 1] cdot (s[i] - a[i][col]) ]

    其中(s[i] = sum_{j = 1} ^ m a[i][j])
    不合法答案即为(sum_{n > j > k} dp[n][j][k])
    但是这样做是(mathcal{O}(m cdot n^3)),考虑到(n le 100,m le 1000),这样完全不行!
    考虑到我们计算答案时并不关心(j,k)的具体数值,指看(j > k),所以我们将第二维变为(j - k)的值,即设(dp[i][x])为用前(i)种烹饪方法,(j - k = x)的情况。
    易得

    [dp[i][x] = dp[i - 1][x] + dp[i - 1][x - 1] cdot a[i][col] + dp[i - 1][x + 1] cdot (s[i] - a[i][col]) ]

    答案为(sum_{x > 0} dp[i][x])。时间复杂度为(mathcal{O}(m cdot n^2))
    发现第二维可能为负,要平移处理。
    这题的dp优化方法值得学习。
    还有就是取模有点奇怪。

    #include <bits/stdc++.h>
    using namespace std;
    # define int long long
    const int N = 105,M = 2005;
    const int mod = 998244353;
    int n,m;
    int f[N][N],dp[N][N << 1];
    int a[N][M],s[N];
    int Hash(int x)
    {
        return x + n + 1;
    }
    signed main(void)
    {
        scanf("%lld%lld",&n,&m);
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++)
                scanf("%lld",&a[i][j]);
        for(int i = 1; i <= n; i++) 
            for(int j = 1; j <= m; j++) s[i] = (s[i] + a[i][j]) % mod;
        f[0][0] = 1;
        for(int i = 1; i <= n; i++)
        {
            for(int j = 0; j <= i; j++) f[i][j] = (f[i - 1][j] + (f[i - 1][j - 1] * (s[i] % mod))) % mod;
        }
        dp[0][Hash(0)] = 1;
        long long ans1 = 0,ans2 = 0;
        for(int col = 1; col <= m; col++)
        {
            memset(dp,0,sizeof(dp));
            dp[0][Hash(0)] = 1ll;
            for(int i = 1; i <= n; i++)
            {
                for(int j = Hash(-i); j <= Hash(i); j++)
                {
                    dp[i][j] = (dp[i - 1][j] + dp[i - 1][j - 1] * (a[i][col] % mod) + dp[i - 1][j + 1] * ((s[i] - a[i][col] + mod) % mod)) % mod;
                }
            }
            for(int i = Hash(1); i <= Hash(n); i++) ans1 = (ans1 + dp[n][i]) % mod;
        }
        for(int i = 1; i <= n; i++) ans2 = (ans2 + f[n][i]) % mod;
        printf("%lld
    ",(ans2 - ans1 + mod) % mod);
    
        return 0;
    }
    
  • 相关阅读:
    第五周笔记
    第四周笔记——复制文件(可读时间)
    第三周笔记
    java第6次作业
    java第五次作业
    java第四次作业
    java第三次作业
    第一周Java笔记
    计划进度表
    第六次作业
  • 原文地址:https://www.cnblogs.com/luyiming123blog/p/15073916.html
Copyright © 2020-2023  润新知