Codeforces 733C (模拟,贪心)

16 篇文章 0 订阅
9 篇文章 0 订阅

题目:http://codeforces.com/contest/733/problem/C
题意:

给你n个数,a1,a2,a3,…an,再给你m个数b1,b2,b3,…bm,问你a序列能否通过合并变成b序列。合并的条件为只能相邻的数合并,ai与ai+1能合并的条件为ai> ai+1或ai< ai+1。合并出来的值为ai+ai+1。然后通过新序列合并下去问你能不能达到b序列?能达到的话输出是如何合并的,不能的话输出NO。

分析:

自己的做法是先分块,看是否可以把一段a分成b。这求一下前缀和然后二分即可。
如果可以,那么接下来合并。从左到右扫描,如果a[j]==a[j+1],那么继续看下一个
否则就可以合并这两个,并且把前面相等的都合并(因为当前两个合并后一定大于前面相等的)
上面就是我一开始的做法,悲剧的是WA在了106个样例上QAQ
存在这样一种情况
3 2 5
按照我的做法,3!=2,那么合并,结果是5 5,剩下的就不能合并了。
修正的做法是判断一下3 2合并后是否等于下一个元素,如果等于,那跳过,先不合并。
否则就可以合并。

自己的做法稍微麻烦了点。因为合并的过程中,应该从最大的开始往左往右合并,这样如果存在可行方案,一定有解。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,char>pii;
const int INF=0x3f3f3f3f;
const int N=1e6+9;
int s[N];
int a[N],b[N],n,m,x[N],pre[N];
pii ans[N];
int main() {
    freopen("f.txt","r",stdin);
    scanf("%d",&n);
    for(int i=1; i<=n; i++) {
        scanf("%d",&a[i]);
        s[i]=s[i-1]+a[i];
    }
    scanf("%d",&m);
    ll sum=0;
    for(int i=1; i<=m; i++) {
        scanf("%d",&x[i]);
        sum+=x[i];
    }
    if(sum!=s[n]) {
        puts("NO");
        return 0;
    }
    sum=0;
    int cnt=0;
    for(int i=1; i<=m; i++) {
        sum+=x[i];
        int g=lower_bound(s+1,s+1+n,sum)-s;
        pre[i]=g;
        if(s[pre[i]]-s[pre[i-1]]!=x[i]) {
            puts("NO");
            return 0;
        }
        int num=0,tsum=0;
        for(int j=pre[i-1]+1; j<pre[i]; j++) {
            tsum+=a[j];
            if(a[j]==a[j+1])
                num++;
            else if(j+2<=pre[i]&&tsum+a[j+1]==a[j+2]) //不加这个判断下面的样例过不了
                num++;
            else if(a[j]<a[j+1]) {
                ans[cnt++]=make_pair(i+1+num,'L');
                while(num) {
                    ans[cnt++]=make_pair(i+num,'L');
                    num--;
                }
                a[j+1]+=tsum;
                tsum=num=0;
            } else if(a[j]>a[j+1]) {
                ans[cnt++]=make_pair(i+num,'R');
                while(num) {
                    ans[cnt++]=make_pair(i+num,'L');
                    num--;
                }
                a[j+1]+=tsum;
                tsum=num=0;
            }
        }
        if(num>0) {
            puts("NO");
            return 0;
        }
    }
    puts("YES");
    for(int i=0; i<cnt; i++)printf("%d %c\n",ans[i].first,ans[i].second);

    return 0;
}
/*
Input
3
3 2 5
1
10

Output
YES
3 L
2 L

*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值