Educational Codeforces Round 91 (Rated for Div. 2) . d Berserk And Fireball

题目链接

https://codeforces.ml/contest/1380/problem/D

前天的cf 到现在才a 我好菜啊 菜鸡爆哭
又是一场unrated 这两天cf测评机炸一场,网站炸一场
就不让人打呗 像掉分都不让

题目思路

题目给出两个数组a,b
给出两种方式将a变成b
第一种是直接将连续的区间长度为k的区间清除 费用为k
第二种是选取两个连续的数 清除小的那个
求把a变成b的最小消费
如果无法将a变成b
则输出-1

这题就直接模拟就好了
但是写不来模拟的我真是写到想死 说到底还是题做少了
首先先判断b上的数大致位置是否和a中一样
如果一样再继续
遍历所有区间
对于不同的区间长度 大体可以分成两类
小于k 和大于等于k的

如果小于k时 只能用第二种方法
但如果此区间中最大值大于区间最近的左值和右值的话
这个区间是无法完全清除的
所以需要记录区间最大值 判断这种情况
如果可以请除 那么这一区间的话费是len*y

当区间长度大于等于k时
两种方法都能做
就先按照比较一二两种方式谁更划算
即比较x和k*y的值
小于等于的话只用第一种方法就好了
花费为len/k+x
大于的话在判断如果此区间是无法完全用第二种方法清除的话(见上一种情况)
我们先就先用第一种方式消去包含最大值的区间 再用第二种就好了
花费为(len-k) * y+x
否则直接用第二种方式清除即可
花费为len * y
还有就是在比较之前可以先将长度除以k的余数用第二种方式清除
具体细节见代码和注释

ac代码

 #include <stdio.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <string.h>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <utility>
#define pi 3.1415926535898
#define ll long long
#define lson rt<<1
#define rson rt<<1|1
#define eps 1e-6
#define ms(a,b) memset(a,b,sizeof(a))
#define legal(a,b) a&b
#define print1 printf("111\n")
using namespace std;
const int maxn = 2e5+10;
const int inf = 0x1f1f1f1f;
const int mod = 2333;

ll a[maxn],pos[maxn],b[maxn];

int main()
{
    //freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
    int n,m;
    scanf("%d%d",&n,&m);
    ll x,k,y;
    scanf("%lld%lld%lld",&x,&k,&y);
    for(ll i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        pos[a[i]]=i;//将a数组中的值的位置记录下来 方便之后的判断和找区间
    }
    a[n+1]=-inf;//这里是当做最后一个区间的右端点 之前写的inf 一直wa 后来发现这样会影响到后面判断区间是否能完全清除 改成了-inf就过了
    for(ll i=1;i<=m;i++)
    {
        scanf("%lld",&b[i]);
    }
    ll flag=0;
    for(ll i=1;i<m;i++)
    {
        if(pos[b[i]]>pos[b[i+1]])
            flag=1;
    }
    if(flag==1)
        printf("-1\n");
    else
    {
        ll l=0,r=0;
        ll ans=0;
        for(ll i=1;i<=m+1;i++)
        {
            if(i==m+1)
                r=n+1;
            else
                r=pos[b[i]];
            if(r-l-1>0)//判断这一段是否有区间需要被消除
            {
                ll maxx=0;
                for(ll j=l+1;j<=r-1;j++)
                {
                    maxx=max(a[j],maxx);
                }
                if(maxx<a[l]|maxx<a[r])//判断区间能否被完全清除
                    flag=0;
                else
                    flag=1;
                if(r-l-1<k)
                {
                    if(flag==1)
                    {
                        printf("-1\n");
                        return 0;
                    }else
                        ans+=(r-l-1)*y;
                }else
                {
                    ll len=r-l-1;
                    ll tem=len%k;
                    ans+=tem*y;
                    len-=tem;
                    if(x<=k*y)
                    {
                        ans+=len/k*x;
                    }else if(flag)
                    {
                        ans+=(len-k)*y+x;
                    }else
                    {
                        ans+=len*y;
                    }
                    flag=0;
                }
            }
            l=r;
        }
        printf("%lld\n",ans);
    }
}

这种模拟还是挺考验码力的 有些细节写搓了就会wa到死 还很难发现
还是要多刷题 码力不够

你可能感兴趣的:(Educational Codeforces Round 91 (Rated for Div. 2) . d Berserk And Fireball)