CF1380D.Berserk And Fireball(思维)

/*
 *CF1380D.Berserk And Fireball
 *n个战士站成一排,分别有武力值ai。
 *你有两种法术:火球和激怒。
 *火球可以消耗x个法力,消灭连续k个战士。
 *激怒可以消耗y个法力,选择相邻的两个战士,武力值大的会消灭武力值小的
 *求最后留下的战士和数组b一样所需要的最小法力花费
 *题解:
 *划分为多个区间
 *如果当前区间的长度len<k
 *区间最大值大于左右端点,则无解,因为无法消去最大值
 *区间最大值小于左右端点,消费就是len*y
 *如果当前区间的长度len>=k
 *区间最大值大于左右端点,那必须花费一个x来把最大值消掉。
 */
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+100;
typedef long long ll;
int a[maxn];
int b[maxn];
ll n,m,x,k,y;
int main () {
    scanf("%lld%lld%lld%lld%lld",&n,&m,&x,&k,&y);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    for (int i=1;i<=m;i++) scanf("%d",&b[i]);
    a[n+1]=b[m+1]=-1;
    ll ans=0;
    for (int i=1,j=0;i<=m+1;i++) {
        int l=j+1,r=j+1,len=0,Max=-1;
        while (r<=n+1&&a[r]!=b[i]) Max=max(Max,a[r]),r++;
        if (r>n+1) {
            ans=-1;break;
        }
        len=r-l;
        if (len<k) {
            if (Max>max(a[l-1],a[r])) {
                ans=-1;break;
            }
            else {
                ans+=y*len;
            }
        }
        else {
            if (Max>max(a[l-1],a[r])) {
                ans+=x;
                len-=k;
                if (x<k*y) 
                    ans+=(len/k)*x+(len%k)*y;
                else
                    ans+=y*len;
            }
            else {
                if (x<k*y)
                    ans+=(len/k)*x+(len%k)*y;
                else
                    ans+=y*len;
            }
        }
        if (a[r]!=b[i])
            j=r+1;
        else
            j=r;
    }
    printf("%lld
",ans);
}
原文地址:https://www.cnblogs.com/zhanglichen/p/13336366.html