Codeforces Round #781 (Div. 2)

A. GCD vs LCM

在这里插入图片描述

Sample input

5
4
7
8
9
10

Sample output

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

题意:

给你一个n,让你构造出四个数a,b,c,d,其中a + b + c + d = n,而且gcd(a,b) = lcm(c,d)

思路:

直接a = n-3,b,c,d = 1就行,下面看代码

#include<bits/stdc++.h>
using namespace std;
const int N = 200010;
void solve(){
    int n;
    scanf("%d",&n);
    printf("%d 1 1 1\n",n-3);
}
int main(){
    int _;
    scanf("%d",&_);
    while(_--) solve();
    return 0;
}

B. Array Cloning Technique

在这里插入图片描述

Sample input

6
1
1789
6
0 1 3 3 7 0
2
-1000000000 1000000000
4
4 3 2 1
5
2 5 7 6 3
7
1 1 1 1 1 1 1

Sample output

0
6
2
5
7
0

题意:

对于一个数组,你可以进行一次操作将这个数组copy一份,也可以进行一次操作从两个数组中选择两个位置进行交换,问你最少需要多少次操作能将这个数组中的所有元素变成一样的值

思路:

首先统计出现最多的数的次数是多少,然后可以遵循一种操作顺序,一定是最优的,就是先copy再交换,假如说一开始最多的数出现的次数是三次的话,那么先copy再交换后的最多的数出现的次数就是6次了,只进行了4次操作,然后会发现每次这种操作都是2的幂次*3,就二分一下就行,下面看代码吧

#include<bits/stdc++.h>
using namespace std;
const int N = 200010;
int n,a[N];
void solve(){
    int n;
    int mx = 0;
    scanf("%d",&n);
    map<int,int> mp;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        mp[a[i]]++;
        mx = max(mx,mp[a[i]]);
    }
    int l = 0,r = 31,ans = -1;
    while(l <= r){
        int mid = l + r >> 1;
        if(mx*(1ll<<mid) >= n) ans = mid,r = mid - 1;
        else l = mid + 1;
    }
    printf("%d\n",ans+n-mx);
}
int main(){
    int _;
    scanf("%d",&_);
    while(_--) solve();
    return 0;
}

C. Tree Infection

在这里插入图片描述

Sample input

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

Sample output

4
4
2
3
4

题意:

一棵树。每秒钟每个有儿子节点感染的节点i,可以感染节点i的一个其他健康儿子节点,同时可以指定一个健康节点感染。问最少多少时间,全部节点感染?

思路:

先预处理出来有多少个连通块,这个连通块意思就是说全都是兄弟节点的块,然后先按照大小次序从大到小染一遍,然后就优先队列染就行,因为目的就是尽可能的让它自己扩散,不是自己染,看代码吧:

#include<bits/stdc++.h>
using namespace std;
const int N = 200010;
int cnt[N],n;
void solve(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) cnt[i] = 0;
    int len = 1;
    for(int i=1;i<n;i++){
        int t;
        scanf("%d",&t);
        cnt[t]++;
        len += cnt[t] == 1;
    }
    sort(cnt+1,cnt+1+n);
    priority_queue<int> q;
    int tim = len;
    for(int i=n;i>=1;i--)
        if(!cnt[i]){
            cnt[i]++;
            break;
        }
    for(int i=n;i>=1;i--){
        if(cnt[i]){
            if(cnt[i] > len) q.push(cnt[i]-len);
            len --;
        }
    }
    len = 1;
    while(!q.empty()){
        int t = q.top();
        q.pop();
        if(t < len) continue;
        len ++;
        tim ++;
        q.push(t - 1);
    }
    printf("%d\n",tim);
}
int main(){
    int _;
    scanf("%d",&_);
    while(_--) solve();
    return 0;
}

D. GCD Guess

在这里插入图片描述

Sample input

2

1

8

1

Sample output

? 1 2

? 12 4

! 4
? 2000000000 1999999999

! 1000000000

题意:

每个询问a,b ,得到输出gcd(a+x,b+x) ,最多询问30次,问x的值是多少,范围(1<=x,a,b<=1e9)

思路:

借鉴了队友的数论的知识,如果a,b都是%(1<<i)为0的,那么gcd(a,b)也都是%(1<<i)为0的,1也一样,那就是判断每一位是否为1就行,因为最多30位,所以询问30次就能出来了,下面看代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 200010;

void solve(){
    long long x = 0;
    for(int i=0;i<30;i++){
        long long a = (1ll<<i) - x;
        long long b = a + (1ll << (i+1));
        printf("? %lld %lld\n",a,b);
        fflush(stdout);
        long long t;
        scanf("%lld",&t);
        if(t % (1ll<<(i+1)) == 0) x += 1ll<<i;
    }
    printf("! %lld\n",x);
    fflush(stdout);
}
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、付费专栏及课程。

余额充值