Educational Codeforces Round 69 (Rated for Div. 2)

文章目录

  • A. DIY Wooden Ladder(思维)
  • B. Pillars(思维)
  • C. Array Splitting(差分)
  • D. Yet Another Subarray Problem(思维)


A. DIY Wooden Ladder(思维)

原题链接:http://codeforces.com/contest/1197/problem/A


题意: 定义 k 阶梯子,两边各一块木板长度至少 k+1,即必须要比台阶数大,中间 k 块木板长度至少为1 。问给你 n 块木板,最多能搭成几阶的梯子。

思路:

  1. 对 n 块木板排序之后,取最长的两块木板搭旁边的两块梯子为最优解.
  2. 剩下的 n-2 块板子,如果全部作为台阶,而其数量大于或等于旁边两块木板较短板长度,则不符,最大值应为旁边两块木板较短板长度减1;如果数量小于旁边两块木板较短板长度,则直接输出台阶数。
  3. 当然,如果木板数小于或等于2,直接输出0即可。

Code(C++):

#include 
#include 
using namespace std;
int a[100010];
int main(){
    int t;  cin>>t;
    while(t--){
        int n;  cin>>n;
        for(int i=0;i<n;i++)
            cin>>a[i];
        sort(a,a+n);
        if(n<=2)
            cout<<0<<endl;
        else{
            if(n-2>=a[n-2]) //台阶数必须要小于第二大根柱子的长度
                cout<<a[n-2]-1<<endl;
            else
                cout<<n-2<<endl;
        }
    }
    return 0;
}


B. Pillars(思维)

原题链接:http://codeforces.com/contest/1197/problem/B

题意: n个柱子上各有一个圆盘, 可以在满足以下条件基础上无限次移动圆盘:

  1. 相邻柱子间
  2. 柱子下面的圆盘半径必须比上面的大或者该柱子为空
  3. 一次只能移动柱子一个圆盘

问是否能够把所有圆盘都移动到一个柱子上?

思路: 先找到所有柱子中圆盘半径最大的那根,然后判断其左边是不是从左到右递增,其右边是不是从右到左递增,若是,则输出“YES”,否则输出“NO”。


Code(C++):

#include 
using namespace std;
int a[200010];
int main(){
    int n;  cin>>n;
    int maxn=-1,pos;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        if(a[i]>maxn){
            pos=i;
            maxn=a[i];
        }
    }
    for(int i=1;i<pos-1;i++){
        if(a[i]>a[i+1]){
            cout<<"NO"<<endl;
            return 0;
        }
    }
    for(int i=pos+1;i<n;i++){
        if(a[i]<a[i+1]){
            cout<<"NO"<<endl;
            return 0;
        }
    }
    cout<<"YES"<<endl;
    return 0;
}


C. Array Splitting(差分)

原题链接: http://codeforces.com/contest/1197/problem/C


题意: 给你长度为n的非递减数组,你需要切为k个连续的子序列数组,每个数组的切分代价是max(a[i])-min(a[j]),现在问你总代价最小是多少?

思路: 先算出所有相邻两数间的差值,共 n-1 个差值。每段子序列的切分代价其实就是该子序列中的所有相邻两数的差值之和,而分成 k 段连续子序列数组也就少了 k 个差值,那么只需要把所有相邻两数间的差值从小到大排序,前 n-k 段差值之和即为最小的切分代价。


Code(C++):

#include 
#include 
using namespace std;
int a[300010],b[300010];
int main(){
    int n,k;
    cin>>n>>k;
    cin>>a[0];
    for(int i=1;i<n;i++){
        cin>>a[i];
        b[i]=a[i]-a[i-1];
    }
    sort(b+1,b+n);
    long long ans=0;
    for(int i=1;i<=n-k;i++)
        ans+=b[i];
    cout<<ans<<endl;
}


D. Yet Another Subarray Problem(思维)

原题链接: http://codeforces.com/contest/1197/problem/D


题意: 给你一个序列,求一个子序列 a[l]~a[r] 能使得该子序列的 sum(l,r)-k*(r-l+1)/m(向上取整)的值是在所有子序列中的最大值并输出该值。特别地,一个长度为0的子序列的答案为0。

思路: 由表达式可知每隔 m 个数就得减掉 k ,所以枚举每一个区间的起点,对原数组进行处理,每隔 m 个数就减掉 k ,然后再确定最大区间和,如果区间和小于0就更新为0。


Code(C++):

#include 
using namespace std;
const int N=3e5+10;
int a[N],b[N];
int main(){
    int n,m,k;
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    long long ans=0;
    for(int j=0;j<m;j++){   //枚举每一个区间的起点
        for(int i=1;i<=n;i++){
            b[i]=a[i];
            if(i%m==j)
                b[i]-=k;
        }
        long long sum=0;
        for(int i=1;i<=n;i++){
            sum+=b[i];
            if(i%m==j)
                ans=max(ans,sum);
            sum=max(sum,0ll);   //如果区间都是负数则更新为0
        }
    }
    cout<<ans<<endl;
    return 0;
}


你可能感兴趣的:(Educational Codeforces Round 69 (Rated for Div. 2))