首页 > 其他分享 >ABC358

ABC358

时间:2024-06-18 09:44:01浏览次数:16  
标签:std int cin ++ vector ABC358 dp

E - Alphabet Tiles

https://atcoder.jp/contests/abc358/tasks/abc358_e

方案数DP。

先看摆花(五年前做过)。

记 \(f_{i,j}\) 表示摆完前 \(i\) 种花,目前已经有了 \(j\) 盆花的方案数。

可以考虑先枚举当前摆第 \(i\) 种花,然后再枚举摆完第 \(i\) 种花之后,目前已经有了 \(j\) 盆花。

不难发现,这种情况下,第 \(i\) 种花有可能摆了 \(0, 1, 2, \ldots, \min(a_i, j)\) 盆。

那么就可以得到:

\[f_{i,j}=(f_{i-1,j}+f_{i-1,j-1}+...+f_{i-1,j-\min(a_i, j)})(f_{0,0}=1) \]

接下来还能滚动优化,从大到小枚举即可,不过我就不接着优化了。

signed main()
{
    std::cin.tie(nullptr)->sync_with_stdio(false);
    int n, m; std::cin >> n >> m;
    std::vector<int> a(n); for (auto& x : a) {std::cin >> x;}
    std::vector<Z> dp(m + 1); dp[0] = 1;
    for (int i = 0; i < n; i++) {
        std::vector<Z> ndp(m + 1);
        for (int j = 0; j <= m; j++) {
            for (int k = 0; k <= a[i] and j + k <= m; k++) {//枚举这种花最多能放几盆
                ndp[j + k] += dp[j];//习惯正推
            }
        }
        dp = ndp;
    }
    std::cout << dp[m] << '\n';
    return 0;
}

再来看这道题,其实也是摆花(字母),但是第 \(i\) 种字母可以随便插入位置,(而不是像本题一样同一种只能放在同一个位置),所以方案数是前 \(i - 1\) 种花的方案数乘以能插入这第 \(i\) 种花的位置方案数,即 \(\binom{n}{k}(n为当前字符串长度,k为要插入的第i种花的数量)\)。

signed main()
{
    std::cin.tie(nullptr)->sync_with_stdio(false);
    int K; std::cin >> K;
    std::vector<Z> dp(K + 1);
    dp[0] = 1;
    for (int i = 0; i < 26; ++i) {
        int C; std::cin >> C;
        std::vector<Z> ndp(K + 1);
        for (int j = 0; j <= K; ++j) for (int k = 0; k <= C and j + k <= K; ++k) {
            ndp[j + k] += dp[j] * comb.C(j + k, k);//n = j + k
        }
        dp = ndp;
    }
    std::cout << std::accumulate(dp.begin() + 1, dp.end(), Z(0)) << '\n';
    return 0;
}

答案是 \(\sum_{i = 1}^K dp_i\),因为他要求长度为 \(1\) 到 \(K\) 之间的字符串的方案数。

G - AtCoder Tour

https://atcoder.jp/contests/abc358/tasks/abc358_g

贪心简化DP

先用贪心简化题目:

  • 显然会停留在一个最大的(路径中的最大),然后不断重复停留。
  • 显然到达最大的(路径中的最大)的之前,路径中不会有环,也就是整个路径中不会有环。

然后设计状态 \(dp_{k, i, j}\) 为第 \(k\) 步走到 \((i, j)\) 格子所能覆盖到的最大数字和,转移即可。

signed main()
{
    std::cin.tie(nullptr)->sync_with_stdio(false);

    int H, W, K; std::cin >> H >> W >> K;
    const int N = H * W, Final_k = std::min(K, N);
    int Si, Sj; std::cin >> Si >> Sj; --Si; --Sj;
    std::vector a(H, std::vector<int>(W)); for (auto& vec : a) for (auto& x : vec) {std::cin >> x;}
    std::vector dp(N + 1, std::vector(H + 1, std::vector<i64>(W + 1, -1))); dp[0][Si + 1][Sj + 1] = 0;

    for (int k = 0; k < Final_k; k++) for (int i = 0; i < H; i++) for (int j = 0; j < W; j++) {//这里第一重循环必须是K,要先把所有坐标的K - 1步处理出来才能保证答案正确
        for (const auto&[dx, dy] : {std::make_pair(0, 1), {0, -1}, {1, 0}, {-1, 0}, {0, 0}}) {//要么相邻的走过来,要么自己停留不动
            int tx = i + dx, ty = j + dy;
            if (tx < 0 or tx >= H or ty < 0 or ty >= W or dp[k][tx + 1][ty + 1] == -1) {continue;}
            dp[k + 1][i + 1][j + 1] = std::max(dp[k + 1][i + 1][j + 1], dp[k][tx + 1][ty + 1] + a[i][j]); 
        } 
    }
	//枚举在哪里之后无限停留
    i64 ans = 0;
    for (int i = 0; i < H; i++) for (int j = 0; j < W; j++) {ans = std::max(ans, dp[Final_k][i + 1][j + 1] + 1LL * a[i][j] * (K - Final_k));}//在(i, j)停留的最大值
    std::cout << ans << '\n';
    return 0;
}

标签:std,int,cin,++,vector,ABC358,dp
From: https://www.cnblogs.com/kdlyh/p/18253743

相关文章

  • 「杂题乱刷」AT_abc358_g
    代码恢复训练2024.6.15(补)链接(luogu)链接(atcoder)abc最水的G了吧。你发现,你最后肯定全在在同一个点上不动,而且你一定可以在\(n\timesm\)回合内走到这个点,因此我们直接\(dp_{i,x,y}\)表示走\(i\)步到\((x,y)\)这个格子所能得到的最大值即可。时间复杂度\(O(......
  • [题解]ABC358E Alphabet Tiles
    AtCoder~E-AlphabetTilesLuogu~ABC358EAlphabetTiles题意简述给定正整数\(K\)和\(C_1,C_2,\dots,C_{26}\)。请求出长度在\(1\)到\(K\)之间,满足下列条件的字符串个数(取模\(998244353\)):该字符串全由大写字母组成。对于\(1\lei\le26\),下面条件成立:设\(a......
  • ABC358
    A.WelcometoAtCoderLand模拟B.TicketCounter模拟代码实现#include<bits/stdc++.h>#definerep(i,n)for(inti=0;i<(n);++i)usingnamespacestd;intmain(){intn,a;cin>>n>>a;vector<int>t(n);......