Codeforces Round #760 (Div. 3)(A~E)题解

Codeforces Round #760 (Div. 3)

A. Polycarp and Sums of Subsequences

题目:——>传送门

题意:有一个长度为3的正整数数组a,将其中三个数中任选一个或两个或三个数组合,可以得到七个数字(七个数中有可能相同)组成数组b, 现在从小到大给你这七个数字,求最初的三个数是多少;

解题思路:由于数组a中都是正整数,那么b中最大的数字就是a中所有数字之和,倒数第二个数字和倒数第三个数字一定是a中两个数字相结合,倒数第四个数字则不一定,例如数组[1,2,10];
那么最后得到的三个数字就是b[7] - b[6],b[7] - b[5],b[7] - (b[7] - b[6]) - (b[7] - b[5]);

AC代码

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
 
void solve(){
    int a[10];
    for(int i = 1; i<=7; i++) scanf("%d", &a[i]);
    int ans = a[7] - a[6];
    int res = a[7] - a[5];
    cout<<ans<<' '<<res<<' '<<a[7] - ans - res<<endl;
    return;
}
 
int main()
{
    int t;
    scanf("%d", &t);
    while(t--){
        solve();
    }
    return 0;
}

B. Missing Bigram

题目:——>传送门

题意:定义一个长度为n的字符串可以被拆分成(n-1)个连续的长度为2的字符串称之为字,例如:“abbaaba” 可以被拆分成"ab", “bb”, “ba”, “aa”, “ab” 和 “ba”.现在小明按顺序给出拆分后的字,但是少了一个字,现在要求构造出一个字符串使得该字符串拆分的字和给出的(n-2)个字的相对顺序相同;

解题思路:直接通过给出的(n-2)个字去构造字符串,第一个字直接加入字符串中,对于后面的字,如果字的第一位和构造字符串的最后一位相同则只加上字的第二位,否则加上整个字;

AC代码

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
 
 
void solve(){
    string c, s;
    s = "";
    int n;
    scanf("%d", &n);
    for(int i = 1; i<=n-2; i++){
        cin>>c;
        if(i == 1) {
            s+=c;
            continue;
        }
        if(c[0] == s[s.length()-1])s+=c[1];
        else s+=c;
    }
    for(int i = s.length(); i<=n-1; i++) s+='a';
    cout<<s<<endl;
    return;
}
 
int main()
{
    int t;
    scanf("%d", &t);
    while(t--){
        solve();
    }
    return 0;
}

C. Paint the Array

题目:——>传送门

题意:给定一个正整数数组a,后把所有元素画成两种颜色。所有能被d整除的元素将被涂成红色,所有其他元素将被涂成蓝色。数组中没有相邻的元素具有相同的颜色, 即找到一个正整数d使得任意相邻的两数中一个能被d整除,一个不能被d整除,或者说不存在输出0;

解题思路:使得相邻的元素没有同样的颜色,则意味着要么从1开始每次每次加2染,要么从2开始每次加2染,首先一点要确定两组数据的最大公约数,然后再将一组数的最大公约数对另一组数便利,看能否整除,另一组同理;

AC代码

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
 
const int N = 105;
ll a[N];
 
void solve(){
    int n;
    scanf("%d", &n);
    for(int i = 1; i<=n; i++) scanf("%lld", &a[i]);
    ll ans = a[1];
    ll res = a[2];
    for(int i = 1; i<=n; i+=2) ans = __gcd(ans, a[i]);
    for(int i = 2; i<=n; i+=2) res = __gcd(res, a[i]);
    int flag = 1;
    for(int i = 2; i<=n; i+=2){
        if(a[i]%ans == 0){
            flag = 0;
            break;
        }
    }
    if(flag){
        cout<<ans<<endl;
        return;
    }
    for(int i = 1; i<=n; i+=2){
        if(a[i]%res == 0){
            puts("0");
            return;
        }
    }
    cout<<res<<endl;
    return;
}
 
int main()
{
    int t;
    scanf("%d", &t);
    while(t--){
        solve();
    }
    return 0;
}

D. Array and Operations

题目:——>传送门

题意:给定一个数组长度为n的数组a,每次可以在数组中选择两个数x,y使得花费值加上x/y下取整,然后从数组中去掉x,y,该操作可以执行k次,保证2*k小于等于n;最后花费值加上剩余的数,求花费值最小的是多少;

解题思路:首先对于选择的数,因为是向下取整,则选择的两个数,大的数为分母,小的为分子,而为使得k次操作后花费的最少,则操作的数范围是将数组从小到大 排序后的[n-2k+1,n];将该段分为[n-2k+1,n-k)和[n-k+1,n],每次取两段中最大的数,若两数相等,则花费加一,否则花费不变;

AC代码

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
 
const int N = 105;
int a[N];
 
void solve(){
    int n, k;
    scanf("%d%d", &n, &k);
    for(int i = 1; i<=n; i++) scanf("%d", &a[i]);
    sort(a+1, a+n+1);
    int ans = 0;
    int res = n-k*2+1;
    for(int i = 1; i<res; i++){
        ans+=a[i];
    }
    for(int i = res; i<=n-k; i++){
        ans+=a[i]/a[k+i];
    }
    cout<<ans<<endl;
    return;
}
 
int main()
{
    int t;
    scanf("%d", &t);
    while(t--){
        solve();
    }
    return 0;
}

E. Singers’ Tour

题目:——>传送门

题意:n个城镇按顺序排成一个圆,城镇编号1~n,每个城镇有一个音乐家,他们在自己城镇开演唱会花费a[i]的时间,然后会按顺序走访每一个城镇,每到下一个城镇演唱会时长就会多出a[i],现在给出各个城镇开演唱会的总时间数组b,求n个城镇的音乐家最开始演唱会的时间,即求数组a;如果无法求得数组a,则输出NO;

解题思路:题目有点像高中的数学公式应用题,根据题意可以知道,对于每一个b[i] = a[i]+2a[i-1]+3a[i-2]……na[i+1];那么所有的b[i]加起来后,每个a[i]的系数都是一样的即为1+2+3……+n可用公式n(n+1)/ 2表示,那么a1+a2+a3……+an的值就是所有的bi加起来除以n*(n+1)/ 2,设此值为S;
接下来,对于相邻的两个城镇:d[i]和d[i-1](i等于1的时候需要特判,下面的推到默认i不等于1);

d[i] = a[i] + 2a[i-1] + 3a[i-2] + ……+na[i+1];
d[i-1] = a[i-1] + 2
a[i-2] + 3a[i-3] + …… + na[i];
令d[i]减去 d[i-1],错位相减,得到a[1]+a[2]+a[3]+……+na[i] = **S+na[i] = d[i] - d[i-1]**
上公式中只有a[i]一个未知数,可以直接求解,注意由于a中都是正整数当判断中出现无法整除的状态即无解;

AC代码

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
 
const int N = 4e4+5;
ll a[N];
ll b[N];
 
void solve(){
    int n;
    scanf("%d", &n);
    ll sum = 0;
    for(int i = 1; i<=n; i++) scanf("%lld", &b[i]), sum+=b[i];
    ll ans = n*(n+1)/2ll;
    if(sum%ans!=0){
        puts("NO");
        return;
    }
    ans = sum/ans;
    for(int i = 1; i<=n; i++){
        int num = i-1;
        if(num == 0) num = n;
        ll res = (b[num] - b[i]+ans);
        if(res%n!=0||res<=0){
            puts("NO");
            return;
        }
        a[i] = res/n;
    }
    puts("YES");
    for(int i = 1; i<=n; i++) printf("%lld ", a[i]);
    puts("");
    return;
}
 
int main()
{
    int t;
    scanf("%d", &t);
    while(t--){
        solve();
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值