codeforces 1380D 模拟+贪心

1380D 1900的题
题意:给你两个数组,长度为n的a【】,和长度为m的b【】,保证数组内的数字不同,你能进行的操作有两个,
op1:选择连续的k个数字,花费x,使其删除
op2:选择连续的两个数字,花费y,删除其中更小的一个
通过这些操作使数组a变为数组b,如果不能则输出-1,如果能则输出最小的花费
思路:这题要注意的主要是爆int范围一直wa6
首先的思路要清晰,对于数组a变为数组b首先要具备的条件就是b是a的子序列。
然后对数组a进行拆分,假设要删去的为(l, r),l和r是不需要删去的,要删去的是(l,r)包含的数
那么对这段长度为len=r-l-1的数组进行讨论,
当这段的最大值不在两端的时候,必须要用一次op1,不然无法删去最大的那个数,如果len<k,那就打印-1
其次,对于op1和op2的贪心,花费x删除k个数,花费y删1个数,
当x<y*k时,表明op1相对于op2是更优的,所以先尽可能的使用op1再使用op2
反之,全部使用op2
具体实现可看代码

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <set>
#include <map>
#include <stack>
#include <unordered_map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
#define rep(i, a, n) for(int i = a; i <= n; i++)
#define per(i, a, n) for(int i = n; i >= a; i--)
#define IOS std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define fopen freopen("file.in","r",stdin);freopen("file.out","w",stdout);
#define fclose fclose(stdin);fclose(stdout);
#define PI 3.14159265358979323846
const int inf = 1e9;
const ll onf = 1e18;
const int maxn = 2e5+10;
inline ll read(){
    ll x=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*f;
}
std::vector<ll> v;
ll a[maxn], b[maxn];
ll n, m, x, k, y;
ll solve(ll l, ll r){
    if(r-l==1) return 0;
    ll mx;ll z = 0;
    for(ll i = l; i <= r; i++){
        if(a[i]>z){
            z=a[i];mx=i;
        }
    }
    ll tmp = 0, len = r-l-1;
    if(mx>l&&mx<r){
        if(len<k) return -1;
        tmp += x;
        len -= k;
    }
    if(x<k*y){
        ll cnt = len/k;
        tmp += cnt*x+(len-cnt*k)*y;
    }else {
        tmp += len*y;
    }
    return tmp;
}
signed main(){
    n=read(), m=read(), x=read(), k=read(), y=read();
    rep(i,1,n) a[i]=read();
    rep(i,1,m) b[i]=read();
    ll pos = 1;
    rep(i,1,n){
        if(a[i]==b[pos]) v.push_back(i), pos++;
    }
    if(pos!=m+1){printf("-1\n");return 0;}
    ll res = 0;
    for(ll i = 0; i <= m; i++){
        ll tmp;
        if(i==0) {
            tmp = solve(0,v[0]); 
            // printf("%d  ", tmp);
            if(tmp!=-1) res+=tmp; 
            else {printf("-1\n");return 0;}
        }else if(i==m) {
            tmp = solve(v[m-1],n+1); 
            // printf("%d ", tmp);
            if(tmp!=-1) res+=tmp; 
            else {printf("-1\n");return 0;}
        }else {
            tmp = solve(v[i-1],v[i]); 
            // printf("%d ", tmp);
            if(tmp!=-1) res+=tmp; 
            else {printf("-1\n");return 0;}
        }
    }
    printf("%lld\n", res);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值