はこねのはこ

はこねさんの備忘録

積(掛け算した値)がオーバーフローするかチェックする

はじめに

ABC169のBで躓いたので。
冷静じゃなくなると間違いが見えなくなる。

結論

一度掛け算し、その積をかけた数の片方で割った場合同じ値になるかをみている。

#define ul unsigned long
bool IsOverflow(ul a, ul b){
    ul x = b * a;
    return (x/a != b);
}

補足

負の数が含まれると不正解パターンがある。
というかコンテスト中にlonglongを用いていて失敗した。

#define ll long long
bool IsOverflow(ll a, ll b){
    ll x = b * a;
    return (x/a != b);
}

これを使ってしまうと下のようになる。
割とトラウマ...。
f:id:hakonebox:20200601223006p:plain

コード

// こっちでも行ける
bool IsOver(ll a, ll b, ll lim){
    return (b > lim/a);
}

// 成功した関数
bool IsOverflow(ul a, ul b){
    ul x = b * a;
    return (x/a != b);
}

// コンテスト中の関数
bool IsOver_ng(ll a, ll b){
    ll x = b * a;
    if(x/a != b){
        return true;
    }else{
        return false;
    }
}


void Main(){
    ul limit = pow(10,18);
    ul n;
    cin >> n;
    vector<ul> a(n);
    for(ul i = 0; i<n;i++){
        cin >> a[i];
        if(a[i] == 0){
            ct(0);
            return;
        }
    }
    ul ans = 1;
    for(ul i = 0; i < n; i++){
        //if(IsOver(ans,a[i], limit)){
        if(IsOverflow(ans,a[i])){
            ct(-1);
            return;
        }else {
            ans *= a[i];
            if ( ans > limit ){
                ct(-1);
                return;
            }
        }
    }
    ct(ans);
    return;
}

int main() {
    Main();
}