Codeforces Round #781 (Div.2) 题解

A. GCD vs LCM

题意:求四个数和等于n,且a,b的最大公因数等于c,d的最小公倍数。

大聪明题一开始还想分奇偶考虑

直接输出 n-3 和3个1就行了,让两个值都为1即可

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define AC return 0;
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    int t;
    cin>>t;
    while(t--){
        int n;
        cin>>n;
        cout<<n-3<<" 1 1 1"<<endl;
    }
    AC
}

B. Array Cloning Technique

题意:一个数组有两个操作复制该数组和交换两个数组中的一个元素

问最小操作次数使数组所有元素都相等

答案由两个操作构成,显然交换次数等于n-一个数最多出现的次数,然后每次复制都是成倍增加,只要考虑什么时候一个数的个数大于等于n即可

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define AC return 0;
const int MAXN=1e5+7;
int a[MAXN];
map<int,int>mp;
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    int t;
    cin>>t;
    while(t--){
        int n;
        cin>>n;
        mp.clear();
        for(int i=1;i<=n;i++){
            cin>>a[i];
            mp[a[i]]++;
        }
        int Max=-1;
        for(int i=1;i<=n;i++){
            if(mp[a[i]]>Max)Max=mp[a[i]];
        }
        if(Max==n)cout<<"0"<<endl;
        else{
            int ans=0;
            ans=n-Max;
            while(Max<n){
                Max=Max*2;
                ans++;
            }
            cout<<ans<<endl;
        }
    }
    AC
}

C. Tree Infection

题意: 给出一棵树,在一秒内可以进行两种操作,如果一个节点有一个孩子感染了那么可以最多感染一个其他孩子,第二种操作任选一个点感染

问最短时间使所有点感染

考虑二分答案加贪心

对于孩子比较多的节点肯定是优先去感染该节点的一个孩子才能使总时间短

注意孩子只能感染孩子,对于节点1来说要把它当成一个独立的点考虑

#include<bits/stdc++.h>
using namespace std;
#define AC return 0;
const int MAXN=2e5+7;
vector<int>vec[MAXN];
vector<int>num;
int siz;
bool check(int tim){
    int sum=tim,add=0;
    for(int i=siz-1;i>=0;i--){
        add+=max(num[i]-sum,0);//孩子之间传播不够,需要第二种操作
        sum--;//从该时间点开始能感染的孩子数
    }
    return add+siz<=tim;//siz表示让每个节点至少有一个孩子感染
}
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    int t;
    cin>>t;
    while(t--){
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)vec[i].clear();
        for(int i=2;i<=n;i++){
            int u;
            cin>>u;
            vec[u].push_back(i);
        }
        num.clear();
        num.push_back(1);//把节点1也放入需要第二种操作感染
        for(int i=1;i<=n;i++)
            if(!vec[i].empty())num.push_back(vec[i].size());
        sort(num.begin(),num.end());
        siz=(int)num.size();
        int l=1,r=n;
        while(l<r){
            int mid=(l+r)>>1;
            if(check(mid))r=mid;
            else l=mid+1;
        }
        cout<<r<<endl;
    }
    AC
}

D. GCD Guess

交互题

题意:猜x值,每次输出a,b返回gcd(x+a,x+b),最多30次询问

考虑判断二进制位,1e9正好可以由30位的二进制数表示,我们每次询问判断该位是0或1

先考虑一个简单的问题,如何判断x是奇数还是偶数,只需要另a为1,b为3,若返回1则为偶数

再考虑一个二进制数111110000,如何判断他的第五位,我们忽略后面的0是不是又变成了判断奇偶数只需另a为16,b为16+16*2即可判断

这样我们的大致思路就有了,我们从最后一位开始判断,记录已经求的数为x,对于第i位来说我们只需要把i位后面全部清0即可,所以在a,b上各加上(1<<(i-1))-x就能把后面的1全部消掉。然后因为进位了,所以在判断该位是1或0上要取反

结合代码再讲一下细节的地方,为什么是i-x而不是2i-x呢?因为假设有一个数是1后面29个0

你在判断第一位时,a为1<<30,b为1<<31就超过题目给的2e9范围

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define AC return 0;
int query(int val,int mul){
    int x;
    printf("? %lld %lld\n",val,val+mul);
    fflush(stdout);
    scanf("%lld",&x);
    return x;
}
signed main(){
    int t;
    scanf("%lld",&t);
    while(t--){
        int x=0;
        for(int i=1;i<=1e9;i=i*2){
            if(query(-x+i,i*2)!=i)x+=i;
        }
        printf("! %lld\n",x);
        fflush(stdout);
    }
    AC
}

E. MinimizOR

假装自己会,其实连题目都没看

#include<bits/stdc++.h>
using namespace std;
#define AC return 0;
signed main(){
    cout<<"good luck"<<endl;
    AC
}

就这么轻松愉快的AK了

第一次写题解 如有错误还请海涵

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值