Codeforces Round #622 (Div. 2)题解(部分)

链接:https://codeforces.com/contest/1313
来源:codeforces

A. Fast Food Restaurant(贪心)

  思路:直接贪心的取,对三个数进行排序,贪心匹配

#include<bits/stdc++.h>
using namespace std;

const int maxn=1e5+10;
int a[maxn];

int main(){
    int T; scanf("%d",&T);
    while(T--){
        scanf("%d%d%d",&a[1],&a[2],&a[3]);
        sort(a+1,a+4);
        if(a[3]==0) puts("0");
        else if(a[2]==0) puts("1");
        else if(a[1]==0){
            int cnt=2;
            a[2]--; a[3]--;
            if(a[2]) cnt++;
            printf("%d\n",cnt);
        }else{
            int cnt=3;
            a[1]--; a[2]--; a[3]--;
            if(a[1]&&a[3]) { a[3]--;a[1]--;cnt++; }
            if(a[2]&&a[3]) { a[3]--;a[2]--;cnt++; }
            if(a[1]&&a[2]) { a[1]--;a[2]--;cnt++; }
            if(a[1]&&a[2]&&a[3]) cnt++;
            printf("%d\n",cnt);
        }
    }
    return 0;
}

B. Different Rules(思维)

  思路: m i n : min: min ( l + r ) − n (l+r)-n (l+r)n   [ 1 , l + r − n ] [1,l+r-n] [1,l+rn] 这个区间的数字无论和谁组合都会小于等于 l + r l+r l+r,所以这些数字无论如何组合都不会大于 [ l + r ] [l+r] [l+r]    m a x : max: max我们考虑 1 1 1 和什么数字相加的时候等于 l + r l+r l+r,那么这个区间以内的数都可以互相结合小于等于 l + r l+r l+r 此区间就是 [ 1 , l + r − 1 ] [1, l+r-1] [1,l+r1]

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

int main(){
    int T; scanf("%d",&T);
    while(T--){
        ll n,l,r;
        scanf("%lld%lld%lld",&n,&l,&r);
        printf("%lld %lld\n",min(max((l+r)-n+1,1ll),n),min(l+r-1,n));
    }
    return 0;
}

C1. Skyscrapers (easy version)(枚举)

  思路:我们枚举每一个峰值,那么他左边的数字一定都是递减的,右边的数字一定都是递增的,直接枚举判断即可。注意数据范围:long long

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn=1e3+10;
int a[maxn],b[maxn];

int main(){
    int n; scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    ll MMax=INT_MIN; int inx=-1;
    for(int i=1;i<=n;i++){
        int Max=a[i]; ll sum=a[i];
        for(int j=i-1;j>=1;j--) { Max=min(a[j],Max); b[i]=Max; sum+=(ll)b[i]; }
        Max=a[i];
        for(int j=i+1;j<=n;j++) { Max=min(a[j],Max); b[i]=Max; sum+=(ll)b[i]; }
        // for(int j=1;j<=n;j++) cout<<b[i]<<" ";
        if(MMax<sum) { MMax=sum;inx=i; }
    }
    int Max=a[inx];
    for(int i=inx;i>=1;i--) { Max=min(a[i],Max); a[i]=Max; }
    Max=a[inx];
    for(int i=inx;i<=n;i++) { Max=min(a[i],Max); a[i]=Max; }
    for(int i=1;i<=n;i++) printf("%d%c",a[i],i==n?'\n':' ');
    return 0;
}

C2. Skyscrapers (hard version)(单调栈)

  思路:此题目相对于上面一题只是数据范围发生了变化,在找峰值的时候,对于左右两边的和我们可以进行优化,我们找到每个数字左侧的小于等于它本身的第一个数,右侧小于等于它本身的最后一个数。(这个过程可以通过单调栈来实现),接下来我们就可以计算出来每一点为峰值的时候它左右两侧的和(两边都是递减的)。然后遍历数组找到和最大的那个点。

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn=5e5+10;
int a[maxn];

stack<int>stk;
int l[maxn],r[maxn];
ll L[maxn],R[maxn];

int main(){
    int n; scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=n;i++){
        while(stk.size()&&a[stk.top()]>a[i]) stk.pop();
        if(stk.empty()) l[i]=0;
        else l[i]=stk.top();
        stk.push(i);
    }
    while(stk.size()) stk.pop();
    for(int i=n;i>=1;i--){
        while(stk.size()&&a[stk.top()]>a[i]) stk.pop();
        if(stk.empty()) r[i]=n+1;
        else r[i]=stk.top();
        stk.push(i);
    }
    //for(int i=1;i<=n;i++) cout<<l[i]<<" "<<r[i]<<endl;
    for(int i=1;i<=n;i++) L[i]=L[l[i]]+1ll*(i-l[i])*a[i];
    for(int i=n;i>=1;i--) R[i]=R[r[i]]+1ll*(r[i]-i)*a[i];
    //for(int i=1;i<=n;i++) cout<<L[i]<<" "<<R[i]<<endl;
    ll MaxUp=INT_MIN; int inx=-1;
    for(int i=1;i<=n;i++){
        ll res=L[i]+R[i]-(ll)a[i];
        if(MaxUp<res){
            MaxUp=res;
            inx=i;
        }
    }
    int MaxPre=a[inx],MaxSuf=a[inx];
    for(int i=inx;i>=1;i--) { MaxPre=min(a[i],MaxPre); a[i]=MaxPre; }
    for(int i=inx;i<=n;i++) { MaxSuf=min(a[i],MaxSuf); a[i]=MaxSuf; }
    for(int i=1;i<=n;i++) printf("%d%c",a[i],i==n?'\n':' ');
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值