Educational Codeforces Round 91 (Rated for Div. 2) D.Berserk And Fireball(思维,暴力破解,分情况)

题目传送
题意:
现在有一个排列,再给出一个删除后的数组,删除操作只有俩种:一种是,选择连续的k个数,删除,消耗x点代价。另一种是,选择连续的俩个数,删除其中小的数,消耗y点代价。现在问,能否得到删除后的数组,如果不能输出-1,如果能,请打出最小代价。

思路:
很明显就是分情况操作,先记录下,每个数的位置,然后在删除后的数组中对应起来,看删除的哪些数,枚举删除的数的最大值(这里要注意,因为区间不会重复,所以我们暴力枚举最大值,最坏也就总共2e5次操作),再看删除的这些数是否满足删除条件。

1.如果y*k大于等于x,那么肯定是代价最小的(每次选择连续的俩个数),但是我们要观察是否满足删除条件,条件:左端点,或者右端点的值要大于这之间的最值
**(1)**如果满足这个条件,那么直接删用y代价,删除端点中间的数即可
(2)如果不满足,那么我们要看是否大于k,如果大于了k,我们就可以用y的代价删除这个最值,而在这之间,我们可以利用这个最值去删除其他数(不用管这个过程,我们只知道留下最值即可),所以代价消耗是x + (中间要删除的个数-k)*y。
如果都不满足这个条件,那么
说明这个数最大值是删不了的
,所以输出-1

2.如果y*k > x,那么我们就要尽量的用x的代价去删除数。条件;删除的数的个数大于等于k
(1)如果满足条件,那么代价为(个数/k)*x + (个数%k)*y
(2)如果不满足条件,那么没办法,我们只能用y的代价去删,那么回到1中所述,寻找最值,如果满足条件就删,不满足退出输出-1

AC代码

#include <bits/stdc++.h>
inline long long read(){char c = getchar();long long x = 0,s = 1;
while(c < '0' || c > '9') {if(c == '-') s = -1;c = getchar();}
while(c >= '0' && c <= '9') {x = x*10 + c -'0';c = getchar();}
return x*s;}
using namespace std;
#define NewNode (TreeNode *)malloc(sizeof(TreeNode))
#define Mem(a,b) memset(a,b,sizeof(a))
#define lowbit(x) (x)&(-x)
const int N = 2e5 + 10;
const long long INFINF = 0x7f7f7f7f7f7f7f;
const int INF = 0x3f3f3f3f;
const double EPS = 1e-7;
const int mod = 1e9+7;
const double II = acos(-1);
const double PP = (II*1.0)/(180.00);
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,ll> piil;
ll arr[N],ans[N],vis[N];
ll solve(ll l,ll r)
{
    ll Max = 0;
    for(ll i = l+1;i < r;i++)
        Max = max(Max,arr[i]);
    return Max;
}//枚举最大值
signed main()
{
    std::ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    //    freopen("input.txt","r",stdin);
    //    freopen("output.txt","w",stdout);
    ll n,m,x,k,y,a = 2,sum = 0,flag = 0,flag1 = 0;
    cin >> n >> m >> x >> k >> y;
    for(ll i = 1;i <= n;i++) {cin >> arr[i];vis[arr[i]] = i;}//记录位置
    for(ll i = 1;i <= m;i++) cin >> ans[i];
    if(ans[1] != arr[1]) a--,ans[0] = arr[1];//这里如果ans[1] != arr[1],说明前面还删了数,还得加个端点进去
    if(ans[m] != arr[n]) ans[++m] = arr[n],flag1 = 1;//与上面同理
    for(ll i = a;i <= m;i++)
    {
        ll l = vis[ans[i-1]],r = vis[ans[i]];//端点位置
        ll num = r-l-1;//中间要删除的个数
        ll Max = solve(l,r);
        if(i == 1) num++,Max = max(Max,arr[l]);//这里注意,如果在上面我们添加了端点进去,那么这个端点其实也是要删的,所以需要更新信息
        if(i == m && flag1) num++,Max = max(Max,arr[r]);//与上同理
        if(num < 0) {flag = 1;break;}//如果位序发生了改变,那么不可能
        if(y*k <= x && (Max < arr[l] || Max < arr[r]))//分情况
            sum += y*num;
        else if(y*k <= x && num >= k)
            sum += (x + (num-k)*y);
        else if(y*k > x && num >= k)
            sum += (num/k*x + (num%k)*y);
        else if(num < k && (Max  < arr[l] || Max < arr[r]))
            sum += y*num;
        else
            {flag = 1;break;}
    }
    if(flag) cout << -1 << endl;
    else cout << sum << endl;
}

猜你喜欢

转载自blog.csdn.net/moasad/article/details/107350479