首页 > 其他 > 详细

CSP-S 2019 Emiya 家今天的饭

时间:2020-01-19 12:59:47      阅读:64      评论:0      收藏:0      [点我收藏+]

\(\text {Emiya 家今天的饭}\)

Emiya 不会让大家饿肚子,所以将做至少一道菜,即 \(k\geq1\)
Rin 希望品尝不同烹饪方法做出的菜,因此她要求每道菜的烹饪方法互不相同
Yazid 不希望品尝太多同一食材做出的菜,因此他要求每种主要食材至多在一半的菜(即\(?k /2?\)道菜)中被使用

subtask1 \(\text {期望得分 64pts}\)

\(f[i][j][k][l]\)\(j, k, l\)分别表示每一列选多少数就行了

subtask2 \(\text {期望得分 84pts}\)

考虑到有且只有一列所选的东西会大于\(?k /2?\)个 即不满足条件

我们可以用容斥定理 用所有情况-不满足条件情况就行了

我们先钦定\(t\) 为选数最多的一列 \(f[i][j][k]\)表示选到了第\(i\)行最多的一行用了\(j\)个 其余列总共选了\(k\)个 答案不满足条件 当切仅当\(j > k\)

转移比较容易
\[f[i][j][k] = f[i - 1][j][k] + f[i - 1][j - 1][k] * a[i][t] + f[i - 1][j][k - 1] *(s[i] - a[i][t])\]

for (int t = 1; t <= m; t ++ ) { 
    memset (f, 0, sizeof (f)); 
    f[0][0][0] = 1; 
    for (int i = 1; i <= n; i ++ ) { 
        for (int j = 0; j <= i; j ++ ) { 
            for (int k = 0; k <= i - j; k ++ ) { 
            f[i][j][k] = f[i - 1][j][k]; 
            if (j) Add (f[i][j][k], f[i - 1][j - 1][k] * a[i][t] % mod); 
            if (k) Add (f[i][j][k], f[i - 1][j][k - 1] % mod * (s[i] % mod - a[i][t] % mod + mod) % mod); 
            f[i][j][k] %= mod; 
            } 
        } 
    } 
    for (int i = 1; i <= n; i ++ ) 
        for (int j = 0; j <= n - i; j ++ ) 
            if (i > j) Add(wrong, f[n][i][j]); 
}

时间复杂度\(O(n^3 *m)\)

std \(\text {期望得分 100pts}\)

考虑如何优化\(f[i][j][k]\)可以直接用差值优化一下

\(f[i][j - k]\)表示选到第几行 最多的一行减去其他行的值为\(j - k\)

考虑\(j - k\)可能为负数 所以我们可以集体向右移\(n\) 然后就行了

\[f[i][j] = f[i -1][j] + f[i - 1][j + 1] * a[i][t] + f[i - 1][j - 1]*(s[i]-a[i][t])\]

int main () {
    read (n); read (m);
    ll ans = 1;
    for (int i = 1; i <= n; i ++ ) for (int j = 1; j <= m; j ++ ) read (a[i][j]), s[i] += a[i][j], s[i] %= mod;
    for (int i = 1; i <= n; i ++ ) ans = (ans * (s[i] + 1)) % mod;
    for (int t = 1; t <= m; t ++ ) {
        memset (f, 0, sizeof (f));
        f[0][n] = 1;
        for (int i = 1; i <= n; i ++ ) {
            for (int j = n - i; j <= n + i; j ++ ) {
                Add (f[i][j], (f[i - 1][j] + f[i - 1][j + 1] * (s[i] - a[i][t]) % mod) % mod);
                if (j >= 1) Add (f[i][j], f[i - 1][j - 1] * a[i][t] % mod);
            }
        }
        for (int i = n + 1; i <= n * 2; i ++ ) Add (wrong, f[n][i]);
    }
    write ((ans % mod - wrong % mod + mod - 1 + mod) % mod);
    return 0;
}

分析

\(64\)难度不大 考场上心态不炸很好拿 难度普及+

\(84\)分需要分析性质 难度提高

\(84->100\)需要经过思考 难度提高+

CSP-S 2019 Emiya 家今天的饭

原文:https://www.cnblogs.com/Hock/p/12213110.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!