Codeforces Round #809 (Div. 2)(C和D1两题)

目录

C. Qpwoeirut And The City

D1. Chopping Carrots (Easy Version)


C. Qpwoeirut And The City

链接:题目链接

 题意:给一个长度为n的数组,一个点同时大于左边和右边,该点为凉爽点(第一和最后不会是),求凉爽点最多时,添加高度最少是多少。

input

6
3
2 1 2
5
1 2 1 4 3
6
3 1 4 5 5 2
8
4 2 1 3 5 3 6 1
6
1 10 1 1 10 1
8
1 10 11 1 10 11 10 1

output

2
0
3
3
0
4

思路:

当长度为奇数时

比如第一个样例,下标i为1-n,那么下标为偶数的点必需是凉爽点,这是直接加起来就行

sum+=max(0LL,max(a[i-1],a[i+1])+1-a[i]);

当长度为偶数时

可以发现第2,3个,第4,5个,第6,7个.....中选一个作为凉爽点,而且不能有相邻

如果第3个为凉爽点,那么后面的就一定是5,7,9...
如果第5个为凉爽点,那么后面的就一定是7,9,11...

也就是从某一处开始选的是右边奇数的,那么后面一定都是选右边奇数,而前边一定都是选左边偶数的

那么记录选左边的从前到后的和x[i],以及选右边的从后到前的和y[i]

答案就是max(x[i]+y[i+1])

    fo(1,n){
        if(i%2==0) x[i/2]+=x[i/2-1]+max(0LL,max(a[i-1],a[i+1])+1-a[i]);      //从前往后
    }
    for(int i=n-1;i>=3;i-=2){
        y[i/2]+=y[i/2+1]+max(0LL,max(a[i-1],a[i+1])+1-a[i]);        //从后往前
    }
    int maxx=1e18;
    for(int i=0;i<n/2;i++) maxx=min(maxx,x[i]+y[i+1]);
    cout<<maxx<<endl;

代码:

#include<bits/stdc++.h>
using namespace std;
#define fo(a,b) for(int i=a;i<=b;i++)
#define mem(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
#define ll long long
#define int long long
#define endl '\n'
#define dou double
const ll mod=1e9+7;
#define M 1000005
int T,n;
int a[M],x[M],y[M];
signed main(){
    cin.tie(nullptr)->sync_with_stdio(false);
    cin>>T;
    while(T--){
        cin>>n;
        int res=n/2-1;
        fo(0,n+1) x[i]=y[i]=0;
        fo(1,n) cin>>a[i];
        fo(1,n){
            if(i%2==0) x[i/2]+=x[i/2-1]+max(0LL,max(a[i-1],a[i+1])+1-a[i]);      //从前往后
        }
        for(int i=n-1;i>=3;i-=2){
            y[i/2]+=y[i/2+1]+max(0LL,max(a[i-1],a[i+1])+1-a[i]);        //从后往前
        }
        if(n%2) cout<<x[n/2]<<endl;
        else{
            int maxx=1e18;
            for(int i=0;i<=res;i++) maxx=min(maxx,x[i]+y[i+1]);
            cout<<maxx<<endl;
        }
    }
    return 0;
}

D1. Chopping Carrots (Easy Version)

链接:题目链接

 题意:给一个数组,需要除一次1~k中的数,然后结果最小和最大的差别最小为多少

input

7
5 2
4 5 6 8 11
5 12
4 5 6 8 11
3 1
2 9 15
7 3
2 3 5 5 6 9 10
6 56
54 286 527 1436 2450 2681
3 95
16 340 2241
2 2
1 3

output

2
0
13
1
4
7
0

 思路:

这个代码是二分做的,先枚举答案,比如问差值为5可以吗,再枚举左端点l(1-3e3),那么右端点就是l+5,遍历数组判断是否都在这个l到r之间,时间复杂度O(n*n*logn)

判断能不能在l到r之间,是让除数为min(k,(a[i]-1)/r+1),保证a[i]除以该数一定是刚好小于等于r的,但是有细节问题,再判断一次min(k,(a[i]-1)/r+1)-1,代码不是有点乱了

类似思路还可以O(n*n)处理以(1-3e3)为右端点,左边最大为多少,更新答案即可,应该也是可以的

代码:

#include<bits/stdc++.h>
using namespace std;
#define fo(a,b) for(int i=a;i<=b;i++)
#define mem(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
#define ll long long
#define endl '\n'
#define dou double
const ll mod=1e9+7;
#define M 1000005
int T,n,k;
int a[M];
int solve(int l,int r){        //判断区间l-r可不可以
    fo(1,n){
        if(l==0){
            if(a[i]/k<l||a[i]/k>r) return 0;
        }
        else if(a[i]<r){
            if(a[i]<l)
                return 0;
        }
        else{
            int res=min(k,(a[i]-1)/r+1);
            if((a[i]/res<l||a[i]/res>r)){
                if(res==1||(a[i]/(res-1)<l||a[i]/(res-1)>r))
                    return 0;
            }
        }
    }
    return 1;
}
int check(int d){        //判断差值为d可不可以
    for(int i=0;i<=3e3;i++){
        if(solve(i,i+d)) return 1;
    }
    return 0;
}
signed main(){
    cin>>T;
    while(T--){
        cin>>n>>k;
        fo(1,n) cin>>a[i];
        int l=0,r=1e4,ans=0;
        while(l<=r){
            int mid=(l+r)/2;
            if(check(mid)){
                r=mid-1;
                ans=mid;
            }else{
                l=mid+1;
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

int 我

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值