CF - 733C 构造 + 贪心

题意:

一排上有n只怪兽,每个重量为ai,每只怪兽可以吃掉比他重量小的怪兽,并获得这个怪兽的重量,问能否在若干步之后形成k只怪兽,每只重量为bi,如果可以,还需要输出在每一步的状态下,左数第几只怪兽吃掉了它左边还是右边的怪兽。

思路:

仔细观察可以发现,ai的相对顺序没变,所以最后形成的bj一定是由某个连续一段的ai组成,所以对于每个ai都可以知道它最后组成了哪个bj。
这样知道ai与bj的配对关系,我们可以按照b的顺序一个一个处理,假设ai,ai+1,…ak组成了bj,那么显然有一种构造方法,让最大的那个ai逐次吃掉其他的。但是这里需要注意的是最大的可能不止一个,我们找到的最大的必须是可以吃掉左边或者右边的那个。这样模拟一下,下标也一起变化就可以了,具体细节见代码。
另外需要注意的一点就是特判,a的和要等于b的和,而且ai一定要能组成某个bj。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 505;

int a[MAXN], b[MAXN];
vector <int> vec[MAXN];

struct node {
    int x;
    char c;
};

int main() {
    //freopen("in", "r", stdin);
    int n, m;
    ll suma = 0, sumb = 0;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
        suma += (ll)a[i];
    }
    scanf("%d", &m);
    for (int i = 1l; i <= m; i++) {
        scanf("%d", &b[i]);
        sumb += (ll)b[i];
    }
    if (suma != sumb) {
        puts("NO");
        return 0;
    }
    ll sum = 0, cn = 0;
    for (int i = 1; i <= m; i++) {
        sum = 0;
        while (cn + 1 <= n && sum + a[cn + 1] <= b[i]) {
            sum += (ll)a[++cn];
            vec[i].push_back(a[cn]);
        }
        if (sum != b[i]) {
            puts("NO");
            return 0;
        }
    }
    bool flag = true;
    vector <node> ans;
    for (int i = 1; i <= m; i++) {
        int Max = vec[i][0], cnt = vec[i].size();
        if (cnt == 1) continue;
        for (int j = 1; j < cnt; j++)
            Max = max(Max, vec[i][j]);
        bool tag = false;
        for (int k = 0; k < cnt; k++) {
            if (vec[i][k] != Max) continue;
            if (k > 0 && vec[i][k] > vec[i][k - 1]) {
                for (int j = k; j > 0; j--)
                    ans.push_back((node){i - 1 + j + 1, 'L'});
                for (int j = k; j < cnt - 1; j++)
                    ans.push_back((node){i, 'R'});
                tag = true;
            }
            else if (k + 1 < cnt && vec[i][k] > vec[i][k + 1]) {
                for (int j = k; j < cnt - 1; j++)
                    ans.push_back((node){i - 1 + k + 1, 'R'});
                for (int j = k; j > 0; j--)
                    ans.push_back((node){i - 1 + j + 1, 'L'});
                tag = true;
            }
            if (tag) break;
        }
        if (!tag) {
            flag = false;
            break;
        }
    }
    if (flag) {
        puts("YES");
        for (int i = 0; i < (int)ans.size(); i++)
            printf("%d %c\n", ans[i].x, ans[i].c);
    }
    else puts("NO");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值