Codeforces Round #825 (Div. 2)

A. Make A Equal to B

在这里插入图片描述

Sample input

5
3
1 0 1
0 0 1
4
1 1 0 0
0 1 1 1
2
1 1
1 1
4
1 0 0 1
0 1 1 0
1
0
1

Sample output

1
2
0
1
1

题意:

你有两个长度为n的数组a和b,你可以进行一次操作,将a数组的某个位置的数取反,或者将这个数组打乱成任意顺序,问将a数组变成b数组最少需要的操作次数是多少

思路:

就统计一下a数组和b数组的’0’的差值的绝对值,然后再统计a数组和b数组不同数的位置的个数,这个不同位置的个数是一定大于等于’0’的差值的绝对值的,如果相等的话那就是这个数,如果大于的话就是差值绝对值+1就行,下面看代码把

#include<bits/stdc++.h>
using namespace std;
const int N = 310;
int a[N],b[N];
void solve(){
    int n;
    scanf("%d",&n);
    int cnt = 0;
    for(int i=1;i<=n;i++) scanf("%d",&a[i]),cnt += a[i];
    for(int i=1;i<=n;i++) scanf("%d",&b[i]),cnt -= b[i];
    int butong = 0;
    for(int i=1;i<=n;i++){
        butong += a[i] != b[i];
    }
    cnt = abs(cnt);
    if(butong == cnt){
        printf("%d\n",cnt);
    }
    else{
        printf("%d\n",cnt+1);
    }
}
int main(){
    int _;
    scanf("%d",&_);
    while(_--) solve();
    return 0;
}

B. Playing with GCD

在这里插入图片描述

Sample input

4
1
343
2
4 2
3
4 2 4
4
1 1 1 1

Sample output

YES
YES
NO
YES

题意:

给你一个长度为n的数组a,问你能不能构造出一个长度为n+1的数组b,使得任意的 i , gcd(b[i],b[i+1]) = a[i]

思路:

gcd(b[i],b[i+1]) = a[i] , gcd(b[i-1,b[i]) = a[i-1],所以说b[i]至少为lcm(a[i-1],a[i]),也可以是lcm(a[i-1],a[i])的倍数,但是越大的话不如越小优,因为越大的话他和他相邻的数的gcd可能会变大,那就可能导致答案错误,思路就是这个,下面看代码吧:

#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int a[N],b[N];
void solve(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    b[1] = a[1],b[n+1] = a[n];
    for(int i=2;i<=n;i++) b[i] = a[i-1]*a[i]/__gcd(a[i-1],a[i]);
    for(int i=1;i<=n;i++){
        if(__gcd(b[i],b[i+1]) != a[i]){
            puts("NO");
            return;
        }
    }
    puts("YES");
}
int main(){
    int _;
    scanf("%d",&_);
    while(_--) solve();
    return 0;
}

C1. Good Subarrays (Easy Version)

在这里插入图片描述

Sample input

3
3
1 2 3
3
1 1 1
4
2 1 4 3

Sample output

6
3
7

题意:

一个数组是好的就意味着这个数组的所有元素值都大于等于它在这个数组中的相对位置,现在给你一个长度为n的数组a,问你它有多少个子数组是好的。

思路:

我想的是dp,f[i]表示的是以第i个数为结尾,最左边能扩展到的位置,如果当前的数为a[i],代表它最大能当a[i]个数的数组的最后一个,转移的时候就只看前一个能扩展到什么位置就行,下面看代码吧

#include<bits/stdc++.h>
using namespace std;
const int N = 200010;
int a[N],f[N];
void solve(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        f[i] = 0;
    }
    f[1] = 1;
    for(int i=2;i<=n;i++){
        f[i] = i;
        if((i-f[i-1]) < a[i]) f[i] = f[i-1];
        else f[i] = max(f[i-1] + 1,i - a[i] + 1);
    }
    long long ans = 0;
    for(int i=1;i<=n;i++) ans += i + 1 - f[i];
    printf("%lld\n",ans);
}
int main(){
    int _;
    scanf("%d",&_);
    while(_--) solve();
    return 0;
}

D. Equal Binary Subsequences

在这里插入图片描述

Sample input

4
2
1010
3
100010
2
1111
2
1110

Sample output

0
1 2
2 3 5
1 2 5
3 2 3 4
1 4
-1

题意:

给你一个长度为2*n的01串,你可以选择一些位置,组成一个子序列,然后将这个子序列循环右移,问你能不能通过最多一次这种操作分出两个长度为n的相同的子序列

思路:

如果1的个数是奇数,那么一定不可能,如果1的个数是偶数,那么一定能构造出来,借鉴了一位大佬的思路,成对的看,下面咱们看一个例子:
1 0 1 0 1 0 1 0
将这个序列循环右移之后的结果就是
0 1 0 1 0 1 0 1
这不就相当于是两两交换吗
然后做法就是两个两个的看,如果主01串相邻两个位置的值不一样就记录一下,都记录的是10这个串的位置,最后两两交换就行,做法就是奇数位置的10的1和偶数位置10的0进行交换,那么这两个位置的值就变成了00和11,那么最后这2n个数的答案就是奇数位置,这个思路非常妙,下面看代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 200010;
char s[N];
void solve(){
    int n;
    scanf("%d%s",&n,s+1);
    n <<= 1;
    vector<pair<int,int> > q;
    for(int i=1;i<=n;i+=2){
        if(s[i] != s[i+1]){
            if(s[i] == '1') q.push_back({i,i+1});
            else q.push_back({i+1,i});
        }
    }
    if(q.size()&1){
        puts("-1");
        return;
    }
    printf("%d ",q.size());
    for(int i=0;i<q.size();i++){
        if(i & 1) printf("%d ",q[i].first);
        else printf("%d ",q[i].second);
    }
    puts("");
    for(int i=1;i<=n;i++) if(i & 1) printf("%d ",i);
    puts("");
}
int main(){
    int _;
    scanf("%d",&_);
    while(_--) solve();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

宇智波一打七~

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

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

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

打赏作者

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

抵扣说明:

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

余额充值