Codeforces Round 1004 Div.2 ABCD题解

这一场真的不难,前四题都是思维题,感觉比上一场Div.4要简单的多

平时没怎么做过交互题,所以花费了太长时间去理解,后面的题补了再写题解

A.Adjacent Digit Sums

题意:给两个数 x , y x,y x,y,看是否有一个数 n n n满足 n n n n + 1 n+1 n+1的数位之和分别等于 x x x y y y

一共分两种情况,对于一个数,如果末位不为9的话,给这个数+1那么数位之和一定会增加1,如果为9的话,那么数位之和会减少 9 ∗ i − 1 9*i-1 9i1 i i i表示这个数末尾9的个数,根据 x x x y y y的关系判断即可

时间复杂度 O ( 1 ) O(1) O(1)

void solve(){
    int x,y;cin>>x>>y;
    if(y>x){
        if(y-x == 1){
            cout<<"Yes"<<endl;
        }
        else{
            cout<<"No"<<endl;
        }
    }
    else{
        if((x-y+1)%9 == 0){
            cout<<"Yes"<<endl;
        }
        else{
            cout<<"No"<<endl;
        }
    }
}

B. Two Large Bags

题意:给出一个有 n n n个数字的集合 A A A,和一个空集合 B B B,可以选择将 A A A中的一个数放到 B B B中或如果两个集合有相同的数,那么将 A A A中的这个数 + 1 +1 +1,求任意次操作后,是否可以将两个集合变成一样的。

这个题我的代码写的很啰嗦,而且思路也比较麻烦,可能中间有一些不需要的操作,或者已经被其他操作包含了,想清楚这个过程就行。

首先可以想到如果有一个数 x x x的个数为 2 2 2,并且集合中存在 x + 1 x+1 x+1,则可以将一个数一直加上去,相当于将后续连续的一些数当作一条路,可以一直加上去,但 x x x的个数会少 1 1 1,注意我们每个数都至少需要 2 2 2个且个数不能为奇数,那么如果集合中 x x x多于 3 3 3个,那么我们可以存起来,直到有一个数的个数为 0 0 0或者为 1 1 1,我们可以用之前存起来的数去补充,直到遇到某个数的个数小于 2 2 2并且存起来的数不够将其补充到 2 2 2,那么如果之前存起来的数还剩 1 1 1个,那么是不可能达到最终要求的,然后再去看后面新的连续的数。用哈希表处理,遍历这个哈希表,将每个数检查一遍即可。

时间复杂度 O ( n ) O(n) O(n)

void solve(){
    int n;cin>>n;
    vector<int>a(n);
    vector<int> has(10005);
    int ma = 0;
    for(int i = 0;i<n;i++){
        cin>>a[i];
        ma = max(ma,a[i]);
        has[a[i]]++;
    }
    int jud = 0;
    int ans = 0;
    for(int i = 1;i<=ma;i++){
        if(has[i] == 0){
            if(ans == 1){
                cout<<"No"<<endl;
                return;
            }
            else if(ans>=2){
                ans-=2;
                has[i] = 2;
            }
            continue;
        }
        if(has[i] == 2){
            continue;
        }
        else if(has[i] == 1){
            if(ans == 0){
                cout<<"No"<<endl;
                return;
            }
            else{
                ans--;
            }
        }
        else if(has[i]>2){
            ans+=has[i]-2;
        }
    }
    if(ans%2 == 1){
        cout<<"No"<<endl;
    }
    else    cout<<"Yes"<<endl;
}

C. Devyatkino

题意:给一个正整数 n n n,可以将其加 9 , 99 , 999 , 9999... , 9,99,999,9999..., 9,99,999,9999...,只包含9的数字,求加到数字中包含 7 7 7至少需要几次

没什么想法的话先打个表,打完表之后就可以发现,如果加9的话,每加一次个位会 − 1 -1 1,十位会 + 1 +1 +1,后面的百位也会增加(个位为0的情况除外,比如90+9 = 99),加99,999的情况同上,最开始我还在算每一位需要加多少次。其实没那么麻烦,因为每加10次就是一个循环,所以直接加 1 0 i − 1 ( 1 < = i < = 10 ) 10^i-1(1<=i<=10) 10i1(1<=i<=10),每个数加10次即可。

我的做法是纯暴力去算,肯定有更快的做法,但是做这个题足够了(其实我打完表之后发现每一个位的变化规律,但是不知道怎么证明为什么不是+99后再+9这种混着加的情况)。

void solve(){
    i64 s;cin>>s;
    int ans = 1e9;
    for(int i = 1;i<=10;i++){
        i64 cnt = 1,tmp = s;
        for(int j = 1;j<=i;j++){
            cnt*=10;
        }
        cnt--;
        for(int j = 1;j<=100;j++){
            i64 b = tmp;
            tmp+=cnt;
            int f = 0;
            while(b){
                if(b%10 == 7){
                    ans = min(ans,j-1);
                    f = 1;
                    break;
                }
                b/=10;
            }
            if(f == 1){
                break;
            }
        }
    }
    cout<<ans<<endl;
}

D. Object Identification

这个题我觉得挺有意思的,首先想到有向图中最短路和坐标中曼哈顿距离最大的区别是,曼哈顿距离没有方向,而图中的边是有方向的,而且图中点的距离范围是比较苛刻的。

如果给出的 x x x不是一个排列,那么至少有一个点的出度是 0 0 0,也就是说以这个点为起点,不管到哪一条边的距离都没有路,题目中这种情况会输出0,而因为没有重合的点,所以在坐标系中不会出现距离为0的情况,直接输出 x x x中不存在的点和其他任意一个点,如果为 0 0 0就是 A A A,如果为 1 1 1就是 B B B

如果是一个排列,注意这个图中点的数量和边的数量相等,这也就限制了任意两点之间的距离 < = n − 1 <=n-1 <=n1,而坐标系中点1到点n的距离一定 > = n − 1 >=n-1 >=n1,我们选择1和n两个点,如果 < n − 1 <n-1 <n1就输出A,如果 > n − 1 >n-1 >n1就输出B,那么等于 n − 1 n-1 n1的情况呢,这时我们进行第二次询问,因为图中 点的数量$ = $边的数量,所以如果存在从 1 1 1 n n n的路径,那么从 n n n 1 1 1的路径这两条路径是不相等的并且有一个为 1 1 1,而坐标系中这两个点的距离是相等的,根据这点可以判断出是哪个图。

void solve(){
    int n;
    cin >> n;
    vector<int> x(n);
    vector<bool> present(n + 1, false);
    for (int i = 0; i < n; ++i) {
        cin >> x[i];
        present[x[i]] = true;
    }
    int u = -1;
    for (int i = 1; i <= n; ++i) {
        if (!present[i]) {
            u = i;
            break;
        }
    }
    if (u != -1) {
        int v = (u == 1) ? 2 : 1;
        cout << "? " << u << " " << v << endl;
        fflush(stdout);
        int res;
        cin >> res;
        if (res == 0) {
            cout << "! A" << endl;
        } else {
            cout << "! B" << endl;
        }
    } else {
        int u,v;
        for(int i = 0;i<n;i++){
            if(x[i] == 1){
                u = i+1;
            }
            if(x[i] == n){
                v = i+1;
            }
        }
        cout << "? " << u << " " << v << endl;
        fflush(stdout);
        int d1;
        cin >> d1;
        if(d1<n-1){
            cout<<"! A"<<endl;
            fflush(stdout);
        }
        else if(d1 > n-1){
            cout<<"! B"<<endl;
            fflush(stdout);
        }
        else{
            cout << "? " << v << " " << u << endl;
            fflush(stdout);
            int d2;
            cin >> d2;
            if (d1 != d2) {
                cout << "! A" << endl;
            } else {
                cout << "! B" << endl;
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值