2017 CCPC秦皇岛 G题 Numbers

DreamGrid has a nonnegative integer . He would like to divide  into nonnegative integers  and minimizes their bitwise or (i.e.  and  should be as small as possible).

Input

There are multiple test cases. The first line of input contains an integer , indicating the number of test cases. For each test case:

The first line contains two integers  and  ().

It is guaranteed that the sum of the length of  does not exceed .

<h4< dd="">Output

For each test case, output an integer denoting the minimum value of their bitwise or.

<h4< dd="">Sample Input

5
3 1
3 2
3 3
10000 5
1244 10

<h4< dd="">Sample Output

3
3
1
2000
125
题解:题意很简单,就是让你把n分成m份,然后让你求这m份按位或的最小值;(注意数据范围,大数模板考虑下Orz)
考虑一个k满足m*2^k <= n < m*2^(k+1)如果使得结果最小,则对于分开后,每个数的最高位(二进制)位置越小,找到一个k后,我们让这m个数字第k位都为一。
然后剩下n-m*2^k(相当于新的n),递归求解即可;
参考代码:
#include <bits/stdc++.h>
using namespace std;
// base and base_digits must be consistent
constexpr int base = 1000000000;
constexpr int base_digits = 9;
struct bigint
{
    vector<int> z;
    int sign;
    bigint() : sign(1) {}
    bigint(long long v)
    {
        *this = v;
    }
    bigint& operator=(long long v)
    {
        sign = v < 0 ? -1 : 1;
        v *= sign;
        z.clear();
        for(; v > 0; v = v / base) z.push_back((int)(v % base));
        return *this;
    }

    bigint(const string& s)
    {
        read(s);
    }

    bigint& operator+=(const bigint& other)
    {
        if (sign == other.sign)
        {
            for (int i = 0, carry = 0; i < other.z.size() || carry; ++i)
            {
                if(i == z.size()) z.push_back(0);
                z[i] += carry + (i < other.z.size() ? other.z[i] : 0);
                carry = z[i] >= base;
                if(carry) z[i] -= base;
            }
        }
        else if (other != 0 /* prevent infinite loop */)
        {
            *this -= -other;
        }
        return *this;
    }

    friend bigint operator+(bigint a, const bigint& b)
    {
        return a += b;
    }

    bigint& operator-=(const bigint& other)
    {
        if (sign == other.sign)
        {
            if (sign == 1 && *this >= other || sign == -1 && *this <= other)
            {
                for (int i = 0, carry = 0; i < other.z.size() || carry; ++i)
                {
                    z[i] -= carry + (i < other.z.size() ? other.z[i] : 0);
                    carry = z[i] < 0;
                    if(carry) z[i] += base;
                }
                trim();
            }
            else
            {
                *this = other - *this;
                this->sign = -this->sign;
            }
        }
        else *this += -other;
        return *this;
    }

    friend bigint operator - (bigint a, const bigint& b)
    {
        return a -= b;
    }

    bigint& operator*=(int v)
    {
        if(v < 0) sign = -sign, v = -v;
        for(int i = 0, carry = 0; i < z.size() || carry; ++i)
        {
            if(i == z.size()) z.push_back(0);
            long long cur = (long long)z[i] * v + carry;
            carry = (int)(cur / base);
            z[i] = (int)(cur % base);
        }
        trim();
        return *this;
    }

    bigint operator*(int v) const
    {
        return bigint(*this) *= v;
    }

    friend pair<bigint, bigint> divmod(const bigint& a1, const bigint& b1)
    {
        int norm = base / (b1.z.back() + 1);
        bigint a = a1.abs() * norm;
        bigint b = b1.abs() * norm;
        bigint q, r;
        q.z.resize(a.z.size());

        for (int i = (int)a.z.size() - 1; i >= 0; i--)
        {
            r *= base;
            r += a.z[i];
            int s1 = b.z.size() < r.z.size() ? r.z[b.z.size()] : 0;
            int s2 = b.z.size() - 1 < r.z.size() ? r.z[b.z.size() - 1] : 0;
            int d = (int)(((long long)s1 * base + s2) / b.z.back());
            r -= b * d;
            while(r < 0) r += b, --d;
            q.z[i] = d;
        }

        q.sign = a1.sign * b1.sign;
        r.sign = a1.sign;
        q.trim();
        r.trim();
        return {q, r / norm};
    }

    friend bigint sqrt(const bigint& a1)
    {
        bigint a = a1;
        while(a.z.empty() || a.z.size() % 2 == 1) a.z.push_back(0);

        int n = a.z.size();
        int firstDigit = (int)::sqrt((double)a.z[n - 1] * base + a.z[n - 2]);
        int norm = base / (firstDigit + 1);
        a *= norm;
        a *= norm;
        while(a.z.empty() || a.z.size() % 2 == 1) a.z.push_back(0);

        bigint r = (long long)a.z[n - 1] * base + a.z[n - 2];
        firstDigit = (int)::sqrt((double)a.z[n - 1] * base + a.z[n - 2]);
        int q = firstDigit;
        bigint res;
        for (int j = n / 2 - 1; j >= 0; j--)
        {
            for(;; --q)
            {
                bigint r1 = (r - (res * 2 * base + q) * q) * base * base + (j > 0 ? (long long)a.z[2 * j - 1] * base + a.z[2 * j - 2] : 0);
                if(r1 >= 0)
                {
                    r = r1;
                    break;
                }
            }
            res *= base;
            res += q;
            if(j > 0)
            {
                int d1 = res.z.size() + 2 < r.z.size() ? r.z[res.z.size() + 2] : 0;
                int d2 = res.z.size() + 1 < r.z.size() ? r.z[res.z.size() + 1] : 0;
                int d3 = res.z.size() < r.z.size() ? r.z[res.z.size()] : 0;
                q = (int)(((long long)d1 * base * base + (long long)d2 * base + d3) / (firstDigit * 2));
            }
        }

        res.trim();
        return res / norm;
    }

    bigint operator/(const bigint& v) const
    {
        return divmod(*this, v).first;
    }

    bigint operator%(const bigint& v) const
    {
        return divmod(*this, v).second;
    }

    bigint& operator/=(int v)
    {
        if(v < 0) sign = -sign, v = -v;
        for (int i = (int)z.size() - 1, rem = 0; i >= 0; --i)
        {
            long long cur = z[i] + rem * (long long)base;
            z[i] = (int)(cur / v);
            rem = (int)(cur % v);
        }
        trim();
        return *this;
    }

    bigint operator/(int v) const
    {
        return bigint(*this) /= v;
    }

    int operator%(int v) const
    {
        if(v < 0) v = -v;
        int m = 0;
        for(int i = (int)z.size() - 1; i >= 0; --i) m = (int)((z[i] + m * (long long)base) % v);
        return m * sign;
    }

    bigint& operator*=(const bigint& v)
    {
        *this = *this * v;
        return *this;
    }

    bigint& operator/=(const bigint& v)
    {
        *this = *this / v;
        return *this;
    }

    bool operator<(const bigint& v) const
    {
        if(sign != v.sign) return sign < v.sign;
        if(z.size() != v.z.size()) return z.size() * sign < v.z.size() * v.sign;
        for(int i = (int)z.size() - 1; i >= 0; i--)
            if(z[i] != v.z[i])  return z[i] * sign < v.z[i] * sign;
        return false;
    }

    bool operator>(const bigint& v) const
    {
        return v < *this;
    }
    bool operator<=(const bigint& v) const
    {
        return !(v < *this);
    }
    bool operator>=(const bigint& v) const
    {
        return !(*this < v);
    }
    bool operator==(const bigint& v) const
    {
        return !(*this < v) && !(v < *this);
    }
    bool operator!=(const bigint& v) const
    {
        return *this < v || v < *this;
    }

    void trim()
    {
        while(!z.empty() && z.back() == 0) z.pop_back();
        if(z.empty()) sign = 1;
    }

    bool isZero() const
    {
        return z.empty();
    }

    friend bigint operator-(bigint v)
    {
        if(!v.z.empty()) v.sign = -v.sign;
        return v;
    }

    bigint abs() const
    {
        return sign == 1 ? *this : -*this;
    }

    long long longValue() const
    {
        long long res = 0;
        for(int i = (int)z.size() - 1; i >= 0; i--) res = res * base + z[i];
        return res * sign;
    }

    friend bigint gcd(const bigint& a, const bigint& b)
    {
        return b.isZero() ? a : gcd(b, a % b);
    }

    friend bigint lcm(const bigint& a, const bigint& b)
    {
        return a / gcd(a, b) * b;
    }

    void read(const string& s)
    {
        sign = 1;
        z.clear();
        int pos = 0;
        while(pos < s.size() && (s[pos] == '-' || s[pos] == '+'))
        {
            if(s[pos] == '-') sign = -sign;
            ++pos;
        }
        for(int i = (int)s.size() - 1; i >= pos; i -= base_digits)
        {
            int x = 0;
            for(int j = max(pos, i - base_digits + 1); j <= i; j++) x = x * 10 + s[j] - '0';
            z.push_back(x);
        }
        trim();
    }

    friend istream& operator>>(istream& stream, bigint& v)
    {
        string s;
        stream >> s;
        v.read(s);
        return stream;
    }

    friend ostream& operator<<(ostream& stream, const bigint& v)
    {
        if(v.sign == -1) stream << '-';
        stream << (v.z.empty() ? 0 : v.z.back());
        for(int i = (int)v.z.size() - 2; i >= 0; --i)
            stream << setw(base_digits) << setfill('0') << v.z[i];
        return stream;
    }

    static vector<int> convert_base(const vector<int>& a, int old_digits, int new_digits)
    {
        vector<long long> p(max(old_digits, new_digits) + 1);
        p[0] = 1;
        for(int i = 1; i < p.size(); i++) p[i] = p[i - 1] * 10;
        vector<int> res;
        long long cur = 0;
        int cur_digits = 0;
        for(int v : a)
        {
            cur += v * p[cur_digits];
            cur_digits += old_digits;
            while (cur_digits >= new_digits)
            {
                res.push_back(int(cur % p[new_digits]));
                cur /= p[new_digits];
                cur_digits -= new_digits;
            }
        }
        res.push_back((int)cur);
        while(!res.empty() && res.back() == 0)
            res.pop_back();
        return res;
    }

    typedef vector<long long> vll;
    static vll karatsubaMultiply(const vll& a, const vll& b)
    {
        int n = a.size();
        vll res(n + n);
        if(n <= 32)
        {
            for (int i = 0; i < n; i++)
                for (int j = 0; j < n; j++)
                    res[i + j] += a[i] * b[j];
            return res;
        }

        int k = n >> 1;
        vll a1(a.begin(), a.begin() + k);
        vll a2(a.begin() + k, a.end());
        vll b1(b.begin(), b.begin() + k);
        vll b2(b.begin() + k, b.end());
        vll a1b1 = karatsubaMultiply(a1, b1);
        vll a2b2 = karatsubaMultiply(a2, b2);
        for(int i = 0; i < k; i++) a2[i] += a1[i];
        for(int i = 0; i < k; i++) b2[i] += b1[i];

        vll r = karatsubaMultiply(a2, b2);
        for(int i = 0; i < a1b1.size(); i++) r[i] -= a1b1[i];
        for(int i = 0; i < a2b2.size(); i++) r[i] -= a2b2[i];
        for(int i = 0; i < r.size(); i++) res[i + k] += r[i];
        for(int i = 0; i < a1b1.size(); i++) res[i] += a1b1[i];
        for(int i = 0; i < a2b2.size(); i++) res[i + n] += a2b2[i];
        return res;
    }

    bigint operator*(const bigint& v) const
    {
        vector<int> a6 = convert_base(this->z, base_digits, 6);
        vector<int> b6 = convert_base(v.z, base_digits, 6);
        vll a(a6.begin(), a6.end());
        vll b(b6.begin(), b6.end());
        while(a.size() < b.size()) a.push_back(0);
        while(b.size() < a.size()) b.push_back(0);
        while(a.size() & (a.size() - 1)) a.push_back(0), b.push_back(0);
        vll c = karatsubaMultiply(a, b);
        bigint res;
        res.sign = sign * v.sign;
        for (int i = 0, carry = 0; i < c.size(); i++)
        {
            long long cur = c[i] + carry;
            res.z.push_back((int)(cur % 1000000));
            carry = (int)(cur / 1000000);
        }
        res.z = convert_base(res.z, 6, base_digits);
        res.trim();
        return res;
    }
};
/***********************************************
     上面为大数模板 核心代码
************************************************/
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    bigint n, m;
    int T;
    cin >> T;
    while(T--)
    {
        cin >> n >> m;
        bigint ans = 0;
        bigint now = 1;
        while(now<= n)
        {
            now = now * 2;
        }
        while(n != 0)
        {
            while(now != 1 && now * m > n)
            {
                now = now / 2;
            }
            if((now * 2 - 1) * m < n)
                now = now * 2;
            bigint num = n / now;
            if(num > m)
                num = m;
            n = n - num * now;
            ans = ans + now;
        }
        cout << ans << endl;
    }
    return 0;
} 

  

猜你喜欢

转载自www.cnblogs.com/songorz/p/9787729.html