专栏文章

题解:AT_abc404_e [ABC404E] Bowls and Beans

AT_abc404_e题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mipdjbrl
此快照首次捕获于
2025/12/03 10:14
3 个月前
此快照最后确认于
2025/12/03 10:14
3 个月前
查看原文

题目大意

nn 个碗编号为 1n11\sim n-1,第 00 个碗中无豆子,第 ii 个碗中有 aia_i 个豆子,它的所有豆子可以移动到前 cic_i 个碗中的任意一个,求将所有碗中的豆子移动到 00 号碗里最少需要几次移动。

解法

我们可以设计一个记忆化搜索:
对于每一个碗,我们记录有那些碗可以把豆子转移到那个碗里。
然后我们可以把它想象成最开始所有豆子都在 00 号碗里,我们要把所有豆子移到有豆子的那些碗里。
我们从 00 号碗开始,向后移动豆子。但我们注意到有豆子的碗是必须得移到的,不然它就会没有豆子,所以在搜索时,记录接下来要到哪一个碗里,每次只要可以从转到那里,那就直接转过去。
但需要注意的是,我们的记忆化搜索 dfs(x) 表示把 x 后面的碗的所有豆子都移到 x 这个碗最少需要几步,所以由于最后一个有豆子的碗及以后的所有碗后面都没有豆子,所以都为 00。(赛时就因为这个没拿分)

代码

CPP
#include <bits/stdc++.h>
#define int long long
const int N = 1e5 + 5;
const int Mod = 1e9 + 7;
using namespace std;
int n;
int sum, ans;
int c[N], a[N];
int f[N];
vector<int> froms[N];
vector<int> toes;
int dfs(int x, int y, int to)
{
    if (f[x])
    {
        return f[x];
    }
    if (x >= toes.back())
    {
        return 0;
    }
    if (x == toes[to])
    {
        to++;
    }
    int mi = 1e18;
    for (int i : froms[x])
    {
        if (i > toes[to])
        {
            continue;
        }
        mi = min(mi, dfs(i, y + 1, to));
    }
    f[x] = mi + 1;
    return mi + 1;
}
signed main()
{
    cin >> n;
    n--;
    for (int i = 1; i <= n; i++)
    {
        cin >> c[i];
        for (int j = i - c[i]; j <= i - 1; j++)
        {
            froms[j].push_back(i);
        }
    }
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        if (a[i])
        {
            toes.push_back(i);
        }
    }
    ans = dfs(0, 0, 0);
    cout << ans;
    return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...