首页 > 其他分享 >Luogu P5664 [CSP-S2019] Emiya 家今天的饭

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

时间:2023-05-19 19:35:23浏览次数:36  
标签:烹饪 P5664 Luogu long 食材 Emiya fi times se

发现“每种主要食材至多在 \(\lfloor \frac{k}{2} \rfloor\) 个菜中被使用”有一个性质,在不合法的情况下绝对只有 \(1\) 个主要食材的个数 \(> \lfloor \frac{k}{2} \rfloor\),因为 \(k - \lfloor \frac{k}{2} \rfloor - 1\le \lfloor \frac{k}{2} \rfloor\)
然后就能发现算不合法的情况比算合法情况好多了啊,因为合法情况的需要考虑所有主要食材,但不合法只需要考虑不合法的这一个主要食材算出其他主要食材组成的方案数即可
所以考虑用总方案数 \(-\) 不合法方案数 \(=\) 合法方案数

考虑算出总方案数,因为每种烹饪方法只能用一次,考虑设 \(f_{i}\) 为前 \(i\) 种烹饪方法的方案数,则对于第 \(i\) 种烹饪方法有两种可能:

  1. 不选第 \(i\) 种烹饪方法,则直接 \(f_i = f_{i - 1}\)
  2. 选第 \(i\) 种方法,因为第 \(i\) 种烹饪方法有 \(h_i = \sum\limits_{j = 1}^m a_{i, j}\) 个菜且因为不关心是否合法任意一种都可以,所以 \(f_i = f_{i - 1}\times h_i\)

综合一下,\(f_i = f_{i - 1} + f_{i - 1}\times h_i\),最后 \(f_n\) 即为总方案数,记得减掉空集产生的 \(1\) 个方案

然后考虑不合法方案数,首先枚举不合法的那一个主要食材 \(1\le i\le m\),然后可以把选的菜的主要食材分为两类:“第 \(i\) 种主要食材”和“非第 \(i\) 种主要食材”
那就可以设 \(g_{j, fi, se}\) 为前 \(j\) 种烹饪方法选了 \(fi\) 个“第 \(i\) 种主要食材”的菜和 \(se\) 个“非第 \(i\) 种主要食材”的菜
那么对于第 \(j\) 种烹饪方法有 \(3\) 种可能:

  1. 不选第 \(j\) 种烹饪方法,\(g_{j, fi, se} = g_{j - 1, fi, se}\)
  2. 选第 \(j\) 种烹饪方法且是第 \(i\) 种主要食材,则有 \(a_{j, i}\) 种菜品可以选择,\(g_{j, fi, se} = g_{j, fi - 1, se}\times a_{j, i}\)
  3. 选第 \(j\) 种烹饪方法且但不第 \(i\) 种主要食材,则有 \(h_j - a_{j, i}\) 种菜品可以选择,\(g_{j, fi, se} = g_{j, fi, se - 1}\times (h_j - a_{j, i})\)

综合一下,\(g_{j, fi, se} = g_{j - 1, fi, se} + g_{j, fi - 1, se}\times a_{j, i} + g_{j, fi , se - 1}\times (h_j - a_{j, i})\),注意一下边界
不合法方案数即为 \(\sum\limits_{fi = 1}^{n}\sum\limits_{se = 0}^{fi - 1} g_{n, fi, se}\),减掉这部分贡献即可

时间复杂度 \(\mathcal{O}(n^3m)\),过不了最后一个 \(\text{Sub}\)

// by lhzawa
#include<bits/stdc++.h>
using namespace std;
const long long mod = 998244353;
const int N = 1e2 + 10, M = 2e3 + 10;
long long a[N][M], h[N];
long long dpc[N], dph[N][N][N];
int main() {
    int n, m;
    scanf("%d%d", &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++) {
            h[i] = (h[i] + a[i][j]) % mod;
        }
    }
    dpc[0] = 1;
    for (int i = 1; i <= n; i++) {
        dpc[i] = (dpc[i - 1] + dpc[i - 1] * h[i] % mod) % mod; 
    }
    long long ans = (dpc[n] - 1 + mod) % mod;
    for (int i = 1; i <= m; i++) {
        dph[0][0][0] = 1;
        for (int j = 1; j <= n; j++) {
            for (int fi = 0; fi <= j; fi++) {
                for (int se = 0; fi + se <= j; se++) {
                    dph[j][fi][se] = dph[j - 1][fi][se];
                    if (se) {
                        dph[j][fi][se] = (dph[j][fi][se] + dph[j - 1][fi][se - 1] * (h[j] - a[j][i] + mod) % mod) % mod;
                    }
                    if (fi) {
                        dph[j][fi][se] = (dph[j][fi][se] + dph[j - 1][fi - 1][se] * a[j][i] % mod) % mod;
                    }
                }
            }
        }
        for (int fi = 1; fi <= n; fi++) {
            for (int se = 0; se < fi; se++) {
                ans = (ans - dph[n][fi][se] + mod) % mod;
            }
        }
    }
    printf("%lld", ans);
    return 0;
}

发现算法的瓶颈在于转移的 \(n^3\) 很难处理,首先 \(j\) 这一维肯定不能去,于是考虑对 \(fi, se\) 这部分进行优化
发现最后的答案只取决于 \(fi > se\),即 \(fi - se > 0\),那就可以想到用 \(fi - se\) 代替 \(fi, se\)
具体的,设 \(g_{j, c}\) 为前 \(j\) 种烹饪方法中“第 \(i\) 种主要食材”的菜的个数 \(-\) “非第 \(i\) 种主要食材”的菜的个数 \(= c\) 的方案数
那么对于第 \(j\) 种烹饪方法有 \(3\) 种可能:

  1. 不选第 \(j\) 种烹饪方法,\(g_{j, c} = g_{j - 1, c}\)
  2. 选第 \(j\) 种烹饪方法且是第 \(i\) 种主要食材,则差值会 \(+1\),\(g_{j, c} = g_{j, c - 1}\times a_{j, i}\)
  3. 选第 \(j\) 种烹饪方法且但不第 \(i\) 种主要食材,则差值会 \(-1\),\(g_{j, c} = g_{j, c + 1}\times (h_j - a_{j, i})\)

时间复杂度 \(\mathcal{O}(n^2m)\)

// by lhzawa
#include<bits/stdc++.h>
using namespace std;
const long long mod = 998244353;
const int N = 1e2 + 10, M = 2e3 + 10;
long long a[N][M], h[N];
long long dpc[N], dph[N][2 * N];
int main() {
    int n, m;
    scanf("%d%d", &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++) {
            h[i] = (h[i] + a[i][j]) % mod;
        }
    }
    dpc[0] = 1;
    for (int i = 1; i <= n; i++) {
        dpc[i] = (dpc[i - 1] + dpc[i - 1] * h[i] % mod) % mod; 
    }
    long long ans = (dpc[n] - 1 + mod) % mod;
    for (int i = 1; i <= m; i++) {
        dph[0][N + 0] = 1;
        for (int j = 1; j <= n; j++) {
            for (int c = N - j; c <= N + j; c++) {
                dph[j][c] = dph[j - 1][c];
                dph[j][c] = (dph[j][c] + dph[j - 1][c + 1] * (h[j] - a[j][i] + mod) % mod) % mod;
                dph[j][c] = (dph[j][c] + dph[j - 1][c - 1] * a[j][i] % mod) % mod;
            }
        }
        for (int c = N + 1; c <= N + n; c++) {
            ans = (ans - dph[n][c] + mod) % mod;
        }
    }
    printf("%lld", ans);
    return 0;
}

标签:烹饪,P5664,Luogu,long,食材,Emiya,fi,times,se
From: https://www.cnblogs.com/lhzawa/p/17416092.html

相关文章

  • 刷题笔记:Luogu P3743
    题目传送门Solution最多能将这些设备一起使用多久,显然答案满足单调性(如果\(x<y\)而不能使用\(x\)时间则一定不能使用\(y\)时间)通俗一点,就是前边的时间不满足则后边一定不满足,也就是局部答案舍弃性,考虑二分时间至于check怎么写呢?和奶牛晒衣服有异曲同工之妙,若设二分出来的时间......
  • 刷题笔记:Luogu P1083 借教室
    题目传送门让结果最接近\(s\)值,显然我们要二分\(w\),check的写法可以直接暴力模拟,如果check(mid)<s则将r右移(通过读公式可以知道\(w\)越小检验值\(y\)就越大)但是这样会TLE,再读一下柿子:\(y_i=\sum\limits_{j=l_i}^{r_i}[w_j\geW]\times\sum\limits_{j=l_i}^{r_i}[w_j\geW]......
  • luogu P8340 [AHOI2022] 山河重整
    题面传送门牛逼题。solution首先来推一推性质。假设我们现在有一个合法的集合,覆盖了\([1,S]\),显然新加进去的数\(i\)不能\(\geqS+2\),而如果\(\leqS+1\)那么\([1,i+S]\)显然可以被覆盖到。因此有一个\(O(n^2)\)的dp:设选到了第\(i\)个数,总和为\(j\),要求\(j\geq......
  • Luogu P5520 [yLOI2019] 青原樱
    考虑先不种花,先算出“花之间空位的可行方案数”\(tot\),乘上花的排列的贡献就能算出答案,即\(tot\timesm!\)为答案所以只需算出“花之间空位的可行方案数”能发现,设\(x_i\)为第\(i\)朵花与第\(i-1\)朵花之间空位的数量,其中设第\(0\)朵花在\(0\)的位置,则发现会有以......
  • luogu P4690 [Ynoi2016] 镜中的昆虫 题解
    P4690[Ynoi2016]镜中的昆虫题解题意维护一个长为 \(n\) 的序列 \(a_i\),有 \(m\) 次操作。将区间 \([l,r]\) 的值修改为 \(x\)。询问区间 \([l,r]\) 出现了多少种不同的数,也就是说同一个数出现多次只算一个。题解感觉这道题还是比较有意思的,像是一堆套路......
  • 【题解】Luogu[P3750] [六省联考 2017] 分手是祝愿
    Link→小清新dp题,纪念自己的700ac(一个点只有两个状态开和不开,且按两下相当于没按,我们可以从大到小有亮的就按一下,如果我们按到了不需要按的键,就需要再按一下使他变回来。设\(f_i\)表示\(i\)个正确选择变为\(i-1\)个的期望操作次数。则有\(\dfrac{i}{n}\)概率按到......
  • 【题解】Luogu[P4900] 食堂
    一到推柿子题。题意即求\(\sum\limits^{n}_{i=1}\sum\limits^{i}_{j=1}\left\{\frac{i}{j}\bmodP\right\}\)对于\(\frac{i}{j}\bmodP\)我们知道即为\(i\)乘上\(j\)的逆元,即为\(i\cdot\mathrm{inv}(j)\)故:\[\begin{aligned}\sum^{n}_{i=1}\sum^{i}_{j=1}\l......
  • 【题解】Luogu[P6003] USACO20JAN Loan Repayment S
    模拟赛第一题(9pts考虑暴力。枚举\(x\),对于每个\(x\),模拟\(k\)天,判断其是否合法,找出最大的\(x\)。时间复杂度:\(O(n^2)\)36pts考虑优化先前暴力算法。我们不难发现当\(x\)合法时,必然有合法\(x_1\),当且仅当\(x_1<x\)。故\(x\)具有单调性,考虑二分答案。对于\(x......
  • 【题解】Luogu[P8818] CSP-S 2022 策略游戏
    一道简单区间rmq分类讨论题,考场上最后5分钟想出来,没写出来,退役了……给定两个序列\(A_{1},\dots,A_{n}\);\(B_1,\dots,B_n\)规定\(C_{i,j}=A_i\timesB_i\)。题目说小L和小Q必定选择最优策略,而小L先选,小Q后选,小L要使得\(C_{i,j}\)尽可能大,小Q要使得\(C_{i,j}\)......
  • 【题解】Luogu[P1879] [USACO06NOV]Corn Fields G
    Link→状压dp典题,看数据范围就能多半猜到是状压。\(M\)行\(N\)列很不舒服,本篇题解规定为\(N\)行\(M\)列。因为说没有哪两块草地相连,我们不妨一行一行考虑,一行中每格只可能是\(0\)或\(1\),所以一行的总不同状态数是\(2^M\)。我们用二进制表示每一行的状态,对于每一行,暴......