Educational Codeforces Round 69 (Rated for Div. 2)

Educational Codeforces Round 69 (Rated for Div. 2)

欢迎参观!!==> 博客地址 <== 欢迎参观!!

暑假跑完步会宿舍Div. 2掉分局,开场三道排序题,D题卡到最后乱搞了思路居然AC了。

[你以为你CF过了4题].jpg

结果喜闻乐见的D题被hack掉了,队友同样死亡。

A. DIY Wooden Ladder

给你n个棍子,要求其中取一些棍子组成梯子,要求满足:

  • 两根木棍长度最少为 k+1 ,作为梯子左右两侧把手
  • k 根梯子,每个长度最小为1,最为梯子的base。

思路:

排序取最长的两根棍子作为把手,第二长的棍子确定k,剩下的全拿过来做base。

代码

#include <bits/stdc++.h>
using namespace std;
#define clr(s) memset(s, 0, sizeof(s))
#define infclr(s) memset(s, 0x3f, sizeof(s))
#define lowclr(s) memset(s, -1, sizeof(s))
#define REP(i, lim) for(int i=0;i<lim;++i)
const int inf = 0x3f3f3f3f;
const int MAXN = 1000005;
 
int len[MAXN];
 
int main()
{
//    freopen("in.txt", "r", stdin);
//    freopen("out.txt", "w", stdout);
    std::ios::sync_with_stdio(false); cin.tie(0);
 
    int T;
    cin>>T;
    while(T--)
    {
        int n;
        cin>>n;
        REP(i, n) cin>>len[i];
        sort(len, len+n, greater<int>());
        int req = len[1] - 1;
        int ans = min(n-2, req);
        cout<<max(0, ans)<<endl;
    }
 
    return 0;
}

ps: 听说群里有大佬认为题目中告诉你有锤子和钉子是可以把两根木棍拼起来,tql


B. Pillars

n n n根柱子,对于每根柱子 a i a_i ai都有一个对应半径为 r i r_i ri的碟子放着,你可以移动柱子上的盘子,每次移动要求满足:

  • 只有相邻的两根棍子上的盘子可以相互移动
  • 盘子a想要放到盘子b上,b的半径必须严格大于a

题目说明每次当一个柱子空了的时候,都会自动有一个新的盘子(半径与原 r i r_i ri相同)出现。

问你是否有可能将所有种类的盘子放到一个柱子上。

思路:

一开始考虑了一下汉诺塔,发现和汉诺塔没什么关系,发现柱子 a a a上的盘子想要移动到柱子b上,a到b的盘子半径就必须是严格递增序列。那么如果想把所有盘子放到一个柱子上,半径最大的盘子两侧必须是严格递减的。

代码

#include <bits/stdc++.h>
using namespace std;
#define clr(s) memset(s, 0, sizeof(s))
#define infclr(s) memset(s, 0x3f, sizeof(s))
#define lowclr(s) memset(s, -1, sizeof(s))
#define REP(i, lim) for(int i=0;i<lim;++i)
const int inf = 0x3f3f3f3f;
const int MAXN = 1000005;
 
int h[MAXN], test[MAXN];
 
int main()
{
//    freopen("in.txt", "r", stdin);
//    freopen("out.txt", "w", stdout);
    std::ios::sync_with_stdio(false); cin.tie(0);
 
    int n;
    cin>>n;
    int maxh = -inf;
    int index = 0;
    REP(i, n){
        cin>>h[i];
        test[i] = h[i];
        if(h[i] > maxh) {
            maxh = h[i];
            index = i;
        }
    }
 
    sort(h, h+index);
    sort(h+index, h+n, greater<int>());
    int f = 1;
    REP(i, n) {
        if(h[i] != test[i]) f = 0;
    }
 
    if(f) cout<<"YES\n";
    else  cout<<"NO\n";
 
    return 0;
}


C. Array Splitting

给定一串有序数组,要求你分成k段。

每次分割的费用为:
∑ i = 1 k ( m a x ( i ) − m i n ( i ) ) \sum_{i=1}^{k}(max(i)−min(i)) i=1k(max(i)min(i))
求最小花费

思路:

共k段,分k-1次,尽可能地将差值大的两个数分开,极为在前 k − 1 k-1 k1大的差值出,分成 k k k

代码:

#include <bits/stdc++.h>
using namespace std;
#define clr(s) memset(s, 0, sizeof(s))
#define infclr(s) memset(s, 0x3f, sizeof(s))
#define lowclr(s) memset(s, -1, sizeof(s))
#define REP(i, lim) for(int i=0;i<lim;++i)
#define ll long long
const int inf = 0x3f3f3f3f;
const int MAXN = 1000005;
 
struct Node{
    int x, l, r;
}node[MAXN];
 
bool cmp(Node A, Node B) {
    return A.x>B.x;
}
 
int cut[MAXN];
 
ll num[MAXN];
 
int main()
{
//    freopen("in.txt", "r", stdin);
//    freopen("out.txt", "w", stdout);
    std::ios::sync_with_stdio(false); cin.tie(0);
 
    int n, k;
    cin>>n>>k;
    int cnt = 0;
    REP(i, n) {
        cin>>num[i];
        if(i>0) {
            node[cnt].x = num[i]-num[i-1];
            node[cnt].l = i-1;
            node[cnt++].r = i;
        }
    }
    sort(node, node+cnt, cmp);
    REP(i, k-1) {
        cut[node[i].l] = 1;
    }
    int now = 0;
    ll sum = 0;
    REP(i, n) {
        if(cut[i] == 1) {
            sum+=(num[i]-num[now]);
            now = i+1;
        }
    }
    sum+=num[n-1]-num[now];
    cout<<sum<<endl;
 
    return 0;
}

D. Yet Another Subarray Problem

给你长度为n的序列,以及两个数值m,k;

子序列的花费为:
∑ i = l r a i − k ⌈ r − l + 1 m ⌉ \sum_{i=l}^{r}a_i-k\lceil \frac{r-l+1}{m} \rceil i=lraikmrl+1
求最大花费:

思路

将公式理解为,子序列和,减去子序列长度除m向上取整次数的k。

因为m很小,所以将减k的操作放在数字中,即在固定位置的数字上减去k。

枚举m的模数,在模数对应的位置上减去k,过程中维护最大值。

代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define REP(i, lim) for(int i=0;i<lim;++i)
#define REPP(i, lim) for(int i=1;i<=lim;++i)
#define clr(s) memset(s, 0, sizeof(s))
#define lowclr(s) memset(s, -1, sizeof(s))
const int inf = 0x3f3f3f3f;
const int MAXN = 1000055;
 
int n,m,k;
int a[MAXN],b[MAXN];
ll ans;
 
int main()
{
//    freopen("in.txt", "r", stdin);
//    freopen("out.txt", "w", stdout);
    std::ios::sync_with_stdio(false); cin.tie(0);
 
    scanf("%d%d%d",&n,&m,&k);
    REPP(i, n)   scanf("%d",a+i);
    REP(j, m){
        REPP(i, n)  b[i]=a[i]-(i%m==j?k:0);
        ll s=0;
        REPP(i, n){
            s=max(s+b[i],0ll);
            if(i%m==j)ans=max(ans,s);
        }
    }printf("%lld\n",ans);
 
    return 0;
}

当天上午多校自闭后,CF被Hack,第二天跟队友约的开封菜早餐也被我

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值