zoukankan      html  css  js  c++  java
  • 【CSP2019】Emiya 家今天的饭

    【CSP2019】Emiya 家今天的饭

    题意

    链接

    题解

    显然根据性质最多的菜品不超过总数量的一半,可以考虑补集转化

    即计算有一个菜品超过数量一半的方案数,再用总方案数减

    总方案数显然可以一个背包搞定(然而我去年就是因为总方案数没求对挂了)

    然后考虑求超过一半的方案数

    枚举当前哪个菜品是超过一半的

    有一个显然的DP:

    $ f_{i,j,k} $ 表示当前到第i行最多的菜品选了j个,其余的选了K个的方案数

    但是这样会T

    考虑能否优化

    注意到我们需要的状态并不需要知道菜品的具体数量,只需要要求菜品的相对数量关系

    于是可以枚举相对数量关系来压缩一维

    #include<bits/stdc++.h>
    
    using namespace std;
    
    #define LL long long 
    
    inline LL read()
    {
        LL x= 0,f = 1;
        char ch;
        do
        {
            ch = getchar();
            if(ch == '-') f = -1;
        }while(ch <'0'||ch >'9');
        do
        {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        }while(ch >= '0' && ch <= '9');
        return f*x;
    }
    
    const int MOD = 998244353;
    const int MAXN = 100 + 10;
    const int MAXM = 2000 + 10;
    
    int n,m;
    LL a[MAXN][MAXM];
    LL tot_meal;
    LL f[MAXN],s[MAXN];
    LL dp[MAXN][MAXN<<1];
    
    int main()
    {
    //    freopen("meal.in","r",stdin);
    //    freopen("meal.out","w",stdout);
        n = read(),m = read();
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                a[i][j] = read();
                s[i] += a[i][j];s[i] %= MOD;
            }
        }
        f[0] = 1;
        for(int i=1;i<=n;i++)
            for(int j=i;j>=1;j--)
                f[j] = (f[j] + f[j-1] * s[i] % MOD) % MOD;
        for(int i=1;i<=n;i++) tot_meal += f[i] ,tot_meal %= MOD;
        //cout << tot_meal << endl;
        LL ans = tot_meal;
        for(register int cur=1;cur<=m;cur++)
        {
            memset(dp,0,sizeof(dp));
            dp[0][n] = 1;
            for(int i=1;i<=n;i++)
            {
                for(int j=1;j<=n+i;j++)
                {
                    dp[i][j] = dp[i-1][j] % MOD;
                    (dp[i][j] += dp[i-1][j+1] * (s[i] - a[i][cur])) %= MOD;
                    (dp[i][j] += dp[i-1][j-1] * a[i][cur]) %= MOD;
                }
            }
            for(int j=n+1;j<=2*n;j++) ans = (ans - dp[n][j] + MOD) % MOD;
        }
        cout << ans << endl;
    }
  • 相关阅读:
    收集邮票
    CF235B Let's Play Osu!
    [SHOI2002]百事世界杯之旅
    路径统计
    fastText 训练和使用
    由最多N个给定数字集组成的数字 Numbers At Most N Given Digit Set
    动态规划-划分数组的最大和 Split Array Largest Sum
    子序列宽度求和 Sum of Subsequence Widths
    Contest 158
    Bert
  • 原文地址:https://www.cnblogs.com/wlzs1432/p/14013262.html
Copyright © 2011-2022 走看看