返回顶部

Codeforces Round #647 (Div. 2) - Thanks, Algo Muse!【ABCD】(题解)

涵盖知识点:暴力、模拟

比赛链接:传送门

A - Johnny and Ancient Computer

题意: 每次只能位移三位以内。不允许右移截断。问最少几次可以使\(a\)变为\(b\)
题解: 不允许截断,所以乘除等价。贪心暴力。
Accept Code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll ;
map<ll,int> check;
int main(){
    for(int i=0;i<=64;i++)check[1ll<<i]=1;
    int t;cin>>t;
    while(t--){
        ll a,b;
        cin>>a>>b;
        if(a>b)swap(a,b);
        ll ans=0;
        while(a<b){
            if(a*8<=b)a*=8,ans++;
            else if(a*4<=b)a*=4,ans++;
            else if(a*2<=b)a*=2,ans++;
            else break;
        }
        cout<<(a==b?ans:-1)<<"\n";
    }
    return 0;
}

B - Johnny and His Hobbies

题意: 问最小的数字\(k\)使得初始集合的每个数都异或\(k\)后集合不变。
题解: 直接暴力。
Accept Code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll ;
int main(){
    int t;cin>>t;
    while(t--){
        int n;
        cin>>n;
        vector<int> a(n);
        set<int> s;
        for(int i=0;i<n;i++){
            cin>>a[i];
            s.insert(a[i]);
        }
        //for(auto i:a)cout<<i<<" ";
        int ans=-1;
        for(int i=1;i<1024;i++){
            bool flag=true;
            for(int j=0;j<n;j++){
                //cout<<a[j]<<" "<<i<<" "<<(a[j]^i)<<"\n";
                //printf("%d\n",s.count(a[j]^i));
                if(s.count(a[j]^i)==0){
                    flag=false;
                    break;
                }
            }
            if(flag){
                ans=i;
                break;
            }
        }
        cout<<ans<<"\n";

    }
    return 0;
}

C - Johnny and Another Rating Drop

题意: 考虑二进制下,定义两个数的差值是不同的位数。求\(1 到 n\)相邻数字的差值的和。
题解: 考虑每一位对总答案的贡献。公式见代码,证明脑补一下应该能脑补出来。
Accept Code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll ;
int main(){
    int t;cin>>t;
    while(t--){
        ll n;
        cin>>n;
        ll ans=0;
        while(n){
            ans+=n;
            n/=2;
        }
        cout<<ans<<"\n";
    }
    return 0;
}

D - Johnny and Contribution

题意: 每篇博客只能覆盖一个主题,但一个主题可以被多个博客覆盖。博客之间有引用的关系。互相引用的博客不能够覆盖同一主题。对于每一个博客,会选择能够覆盖的最小主题进行覆盖。求顺序完成博客以满足给定的引用关系。
题解: 抽象成图以后根据每个顶点的属性从小到大进行排序。然后依次安排,分别检测所连接的点是否含有相同属性,并且是否覆盖小于该属性的所有正整数即可。
Accept Code:

#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int maxn=5e5+10;
int c[maxn];
vector<int> g[maxn];
pii rec[maxn];

int main() {
    int n, m;
    cin >> n >> m;
    for (int i = 0,a,b; i < m; i++) {
        cin>>a>>b;
        a--,b--;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    for (int i = 0,t; i < n; i++) {
        cin>>t;
        rec[i] = {t,i};
    }
    sort(rec, rec + n);
    for (int i = 0; i < n; i++) {
        int node = rec[i].second;
        int col = rec[i].first;
        set<int> bs;
        for (int j : g[node]) {
            int ncol = c[j];
            if (ncol && ncol < col)
                bs.insert(ncol);
            if (ncol == col) {
                cout << -1 << "\n";
                return 0;
            }
        }
        if (bs.size() == col - 1)c[node] = col;
        else {
            cout << -1 <<"\n";
            return 0;
        }
    }
    for (int i = 0; i < n; i++) {
        cout << rec[i].second + 1 << ' ';
    }
    cout << "\n";
}

posted @ 2020-06-05 14:57  Charles1999  阅读(180)  评论(0编辑  收藏  举报