【ABC 301】D 思维

D

这道题被卡了很久。。。惭愧。。。

题意

给你一个由[0,1,?]组成的字符串S和一个数NN1018),你可以把一个 ? 变成 0 或者 1,问S最大能表示的不超过N的数是多少。

正解

先判断 -1 的情况:S能表示的最小的数是所有❓都填0所表示的数字,如果这个数都大于N,肯定是无解的,否则有解

策略:如果某一位❓填1仍然N,就填1,否则填0

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5 + 10;
string s, t;
ll n, ans;

int main() {
    cin >> s >> n;
    int len = s.length(); 
    for(int i = 0; i < len; i++) {
        if(s[i] == '1') ans |= (1ll << (len - 1 - i));
    }
    if(ans > n) {
        puts("-1");
        return 0;
    }
    for(int i = 0; i < len; i++) {
        if(s[i] == '?') {
            if((ans | (1ll << (len - 1 - i))) <= n) ans |= (1ll << (len - 1 - i));
        }
    }
    printf("%lld\n", ans);
    return 0; 
}

我的错解

我的思路不是比较数值大小,是比较字符串(没过脑。。。。)

错的点在于考虑漏了一种情况(悲,修改后即可ac

debug超久总算ac的shishan代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5 + 10;
string s, t;
ll n;

int main() {
    cin >> s >> n;
    int len = s.length();   // 2 ^ [len - 1, ... ,0]

    // n转字符串
    for(int i = 0; i <= 60; i++) {
        if((n & (1ll << i)) != 0) t.push_back('1'), n -= (1ll << i);
        else t.push_back('0');
        if(!n) break;
    }
    reverse(t.begin(), t.end());
    // cout << "t :  " << t << endl; /// 

    // t更长 直接输出
    if(t.length() > len) {
        ll ans = 0;
        for(int i = 0; i < len; i++) {
            if(s[i] != '0') ans = ans * 2 + 1;
            else ans *= 2;
        }
        cout << ans << endl;
        return 0;
    }

    // t短 补全
    if(t.length() < len) {
        int times = len - t.length();
        for(int i = 1; i <= times; i++) t = "0" + t;
        // cout << "t :  " << t << endl; /// 
    }

    // 找 最初的上1下0 并看是否能补救    !!!!!!WA的原因:10之前可能已经有01了,修改后即可ac
    int flag = -1;
    bool occur = 0;
    for(int i = 0; i < len; i++) {
        if(s[i] == '1' && t[i] == '0' && !occur) {
            flag = i;
            break;
        }
        if(s[i] == '0' && t[i] == '1') {
            occur = 1;
            break;
        }
    }
    if(flag != -1) {
        bool ok = 0;
        for(int i = flag - 1; i >= 0; i--) {
            if(t[i] == '1' && (s[i] == '0' || s[i] == '?')) {
                ok = 1;
                s[i] = '0';
                break;
            }
        }
        if(!ok) {
            puts("-1");
            return 0;
        }
    }

    // 照搬 or 可以全1
    bool f = 0;
    for(int i = 0; i < len; i++) {
        if(s[i] == '?') {
            if(!f) s[i] = t[i];
            else s[i] = '1';
        }
        else {
            if(s[i] == '0') {
                if(!f && t[i] == '1') f = 1;
            }
        }
    }
    ll ans = 0;
    for(int i = 0; i < len; i++) {
        if(s[i] == '1') ans = ans * 2 + 1;
        else ans *= 2;
    }
    cout << ans << endl;
    return 0; 
}

总结

这次的D题让我想到了以前的很多时刻。

我总是这样,常常出现在写模拟题的时候,在思路还不明晰的时候匆忙开始,然后一直一直debug,最后还不保证能解决问题。

我把它总结为因为一时的懒惰而要花费巨大的代价(比如这次还用Mac对拍了,虽说这也是必备技能)去弥补。

得 不 偿 失 。

以后再遇到类似的情况,我一定要先在纸上写下清晰的过程,再开始做。

谢谢trq让我意识到这个问题,看来我还有很大的上升空间呀(

posted @   starlightlmy  阅读(37)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示