Codeforces Round #826 (Div. 3)

CC. Minimize the Thickness

在这里插入图片描述

Sample input

4
6
55 45 30 30 40 100
4
10 23 7 13
5
10 55 35 30 65
6
4 1 1 1 1 4

Sample output

3
4
2
3

题意:

给你一个长度为n的数组a,你可以将数组a划分为很多个段,每段之和相同,问你所有划分方式中的最大分段长度的最小值是多少

思路:

可以枚举第一个分段到了哪一个位置,然后这个和就出来了,然后对后面的数进行二分,复杂度就是O(nlog(n)),下面看代码把

#include<bits/stdc++.h>
using namespace std;
const int N = 2010;
int n,a[N],mx;
long long s[N];
bool dfs(int u,int len){
    if(u > n) return true;
    int l = u,r = n,ans = -1;
    while(l <= r){
        int mid = l + r >> 1;
        if(s[mid] - s[u-1] >= len) ans = mid,r = mid - 1;
        else l = mid + 1;
    }
    if(ans == -1 || s[ans] - s[u-1] != len) return false;
    mx = max(mx,ans-u+1);
    return dfs(ans+1,len);
}
void solve(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]),s[i] = s[i-1] + a[i];
    int res = n;
    for(int i=1;i<=n;i++){
        long long cnt = s[i] - s[0];
        int l = i + 1,r = n,ans = -1;
        mx = i;
        if(!cnt || (s[n]-s[i])%cnt){
            continue;
        }
        if(dfs(i+1,cnt)) res = min(res,mx);
    }
    printf("%d\n",res);
}
int main(){
    int _;
    scanf("%d",&_);
    while(_--) solve();
    return 0;
}

D. Masha and a Beautiful Tree

在这里插入图片描述
在这里插入图片描述

Sample input

4
8
6 5 7 8 4 3 1 2
4
3 1 4 2
1
1
8
7 8 4 3 1 2 6 5

Sample output

4
-1
0
-1

题意:

给你一棵完全二叉树,这棵树的所有叶子节点有n个,组成了一个排列,你可以进行一次操作将具有相同父节点的两个节点交换位置,问你最少需要多少次交换能使得这n个叶节点形成一个1-n的排列

思路:

首先看第一步,一定是先换两两相邻的兄弟节点,而且这两个兄弟节点如果相差不为1这棵树就无解,先把所有的叶子节点换成兄弟两个顺序正确,然后发现可以将两个节点归成一个,继续进行这个操作,把这个新归成的节点就是他们的除以二上取整 ,然后最后归成1就结束了,下面看代码把

#include<bits/stdc++.h>
using namespace std;
void solve(){
    int n;
    scanf("%d",&n);
    vector<int> b[30];
    for(int i=1;i<=n;i++){
        int x;
        scanf("%d",&x);
        b[0].push_back(x);
    }
    long long ans = 0;
    for(int k=0;k<30;k++){
        if(b[k].size() == 1) break;
        for(int i=0;i<b[k].size();i+=2){
            if(abs(b[k][i]-b[k][i+1]) != 1){
                puts("-1");
                return;
            }
            ans += b[k][i] > b[k][i+1];
            b[k+1].push_back((b[k][i]+1)/2);
        }
    }
    printf("%lld\n",ans);
}
int main(){
    int _;
    scanf("%d",&_);
    while(_--) solve();
    return 0;
}

E. Sending a Sequence Over the Network

在这里插入图片描述

Sample input

7
9
1 1 2 3 1 3 2 2 3
5
12 1 2 7 5
6
5 7 8 9 10 3
4
4 8 6 2
2
3 1
10
4 6 2 1 9 4 9 3 4 2
1
1

Sample output

YES
YES
YES
NO
YES
YES
NO

题意:

给你一个长度为n的数组,你需要将这个数组分成若干段,每一段的前面或者后面必须有一个值表示这一段的长度,暂且叫这个数为标签吧,作为标签的数就不能出现在任何区间里面,问你有没有一种划分方法满足上述题意

思路:

f[i]表示的是第1-i个数能不能划分出来,然后转移的话就是第i个数作为左标签,第i个数作为右端点这两个,代码很简单,下面看代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 200010;
typedef long long LL;
LL f[N];
int a[N];
void solve(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]),f[i] = 0;
    f[0] = 1;
    for(int i=1;i<=n;i++){
        if(f[i-1] && i+a[i] <= n) f[i+a[i]] = 1;
        if(i>a[i] && f[i-a[i]-1]) f[i] = 1;
    }
    puts(f[n]?"YES":"NO");
}
int main(){
    int _;
    scanf("%d",&_);
    while(_--) solve();
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

宇智波一打七~

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

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

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

打赏作者

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

抵扣说明:

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

余额充值