Codeforces Round #852 (Div. 2)

Posted on 2023-02-12 19:31  Capterlliar  阅读(156)  评论(0编辑  收藏  举报

A. Yet Another Promotion

题意:买土豆,一种卖a元一公斤,买m公斤送一公斤;一种卖b元一公斤。求买n公斤土豆最少花多少钱。

解:完全没有思考,把a*n, b*n, 买尽可能多m倍数的土豆剩下的都买a和都买b,四种情况堆上去取min。

B. Fedya and Array

题意:令一序列相邻两个元素之差为1(一头一尾也算相邻),如果一个数大于它左右两边,称其为局部最大;小于两边则为最小。现给出所有局部最大之和为x,局部最小之和为y,求任意满足要求的最短序列。

解:画一画大概是一个折线图,观察一下发现所有局部最大之和与局部最大个数没啥关系,再观察一下样例,序列长度为最大最小值相差距离的两倍。那么构造一个序列,其最小值为y,最大值为x,然后两边连起来即可。例如:x=2, y=-1,序列可以是-1, 0, 1, 2, 1, 0.

C. Dora and Search

题意:给出一个排列,求其一个子数组,使得子数组两端都不是该子数组最大值,也不是该子数组最小值。

解:试图枚举每个元素作为左端点,寻找右端点。预处理出每个元素右起第一个大于/小于它的元素位置,这个过程可以用单调栈解决。假设第一个大于它的位置为n,第一个小于它的位置为m,那么我们只能取位置大于等于max(m, n)的元素,才能使得当前元素不是最值。现在考虑判断右端点是否会为最值,同样地预处理出每个元素向左第一个大于/小于它的数的位置,看当前元素是否在这个范围外。

upd:早上醒来发现昨天时间复杂度是算错的,但应该跑不满n2,有没有好心人算算(

代码:

#include <bits/stdc++.h>
using namespace std;
#define maxx 200005
#define maxn 25
#define maxm 205
#define ll long long
#define inf 1000000009
#define mod 2520
int a[maxx]={0};
int biggerleft[maxx]={0};
int biggerright[maxx]={0};
int smallerleft[maxx]={0};
int smallerright[maxx]={0};
stack<int> s;
signed main(){
    int T;
    scanf("%d",&T);
    while(T--) {
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        while (!s.empty()) s.pop();
        for(int i=1;i<=n;i++){
            while(!s.empty() && a[s.top()] >= a[i]) s.pop();
            if(!s.empty()) smallerleft[i]=s.top();
            else smallerleft[i]=-1;
            s.push(i);
        }
        while (!s.empty()) s.pop();
        for(int i=1;i<=n;i++){
            while(!s.empty() && a[s.top()] <= a[i]) s.pop();
            if(!s.empty()) biggerleft[i]=s.top();
            else biggerleft[i]=-1;
            s.push(i);
        }
        while (!s.empty()) s.pop();
        for(int i=n;i>=1;i--){
            while(!s.empty() && a[s.top()] >= a[i]) s.pop();
            if(!s.empty()) smallerright[i]=s.top();
            else smallerright[i]=-1;
            s.push(i);
        }
        while (!s.empty()) s.pop();
        for(int i=n;i>=1;i--){
            while(!s.empty() && a[s.top()] <= a[i]) s.pop();
            if(!s.empty()) biggerright[i]=s.top();
            else biggerright[i]=-1;
            s.push(i);
        }
        int flag=0;
        for(int i=1;i<=n;i++){
            if(smallerright[i]==-1||biggerright[i]==-1) continue;
            int r=max(smallerright[i],biggerright[i]);
            for(int j=r;j<=n;j++){
                if(smallerleft[j]==-1||biggerleft[j]==-1) continue;
                int l=min(smallerleft[j],biggerleft[j]);
                if(i<=l){
                    printf("%d %d\n",i,j);
                    flag=1;
                    break;
                }
            }
            if(flag) break;
        }
        if(!flag) printf("-1\n");
    }
    return 0;
}
View Code

D. Moscow Gorillas

题意:给出两个长度相同的排列,求有多少个区间使得两序列在该区间MEX相同。

解:先观察一下,首先整个排列MEX相同,其次每单个数,除了1,MEX也相同。考虑枚举MEX。如果两个区间MEX相同,那么它们包含1-x-1,同时不包含x。单独考虑1,答案为两序列中都不包含1的区间。对于MEX≥2,预处理两个序列都包含1-x-1的区间,然后根据x的位置向左向右扩展,将扩展部分相乘即可。