1 条题解

  • 3
    @ 2023-10-19 23:57:19

    由于数值有正有负,所以需要分类讨论。

    • 第一个人拿非负数max\max ,则第二个人为了乘积小,必须拿负数min\min
    • 第一个人拿非负数min\min ,则第二个人为了乘积小,必须拿负数min\min
    • 第一个人拿负数max\max ,则第二个人为了乘积小,必须拿正数max\max
    • 第一个人拿负数min\min ,则第二个人为了乘积小,必须拿正数max\max

    故而我们需要维护两个序列的非负数 max,min\max,\min 以及负数的 max,min\max,\min

    其实再细分一下可以少一些情况,这里留给读者思考吧,每个数列需要维护四个区间静态最值,一共要维护 88 个,笔者采用维护 88 个 ST 表,然后分类求解,分类时需要特判如果这个区间就不存在负数或非负数等情况

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int N = 1e5 + 5;
    ll n, m, a[N], b[N], q;
    ll fmxa[N][17], fmna[N][17], gmxa[N][17], gmna[N][17];
    ll fmxb[N][17], fmnb[N][17], gmxb[N][17], gmnb[N][17];
    void init()
    {
        for (int i = 1; i <= n; i++)
        {
            if (a[i] >= 0)
            {
                fmxa[i][0] = fmna[i][0] = a[i];
                gmxa[i][0] = -1e9, gmna[i][0] = 1e9;
            }
            else
            {
                fmxa[i][0] = -1e9, fmna[i][0] = 1e9;
                gmxa[i][0] = gmna[i][0] = a[i];
            }
        }
        for (int i = 1; i <= m; i++)
        {
            if (b[i] >= 0)
            {
                fmxb[i][0] = fmnb[i][0] = b[i];
                gmxb[i][0] = -1e9, gmnb[i][0] = 1e9;
            }
            else
            {
                fmxb[i][0] = -1e9, fmnb[i][0] = 1e9;
                gmxb[i][0] = gmnb[i][0] = b[i];
            }
        }
        for (int j = 1; (1 << j) <= n; j++)
        {
            for (int i = 1; i + (1 << j) - 1 <= n; i++)
            {
                fmxa[i][j] = max(fmxa[i][j - 1], fmxa[i + (1 << (j - 1))][j - 1]);
                gmxa[i][j] = max(gmxa[i][j - 1], gmxa[i + (1 << (j - 1))][j - 1]);
                fmna[i][j] = min(fmna[i][j - 1], fmna[i + (1 << (j - 1))][j - 1]);
                gmna[i][j] = min(gmna[i][j - 1], gmna[i + (1 << (j - 1))][j - 1]);
            }
        }
        for (int j = 1; (1 << j) <= m; j++)
        {
            for (int i = 1; i + (1 << j) - 1 <= m; i++)
            {
                fmxb[i][j] = max(fmxb[i][j - 1], fmxb[i + (1 << (j - 1))][j - 1]);
                gmxb[i][j] = max(gmxb[i][j - 1], gmxb[i + (1 << (j - 1))][j - 1]);
                fmnb[i][j] = min(fmnb[i][j - 1], fmnb[i + (1 << (j - 1))][j - 1]);
                gmnb[i][j] = min(gmnb[i][j - 1], gmnb[i + (1 << (j - 1))][j - 1]);
            }
        }
    }
    int queryfmxa(int l, int r)// a 正数的max
    {
        int k = log2(r - l + 1);
        return max(fmxa[l][k], fmxa[r - (1 << k) + 1][k]);
    }
    int queryfmna(int l, int r)// a 正数的min
    {
        int k = log2(r - l + 1);
        return min(fmna[l][k], fmna[r - (1 << k) + 1][k]);
    }
    int queryfmxb(int l, int r)// b 正数的max
    {
        int k = log2(r - l + 1);
        return max(fmxb[l][k], fmxb[r - (1 << k) + 1][k]);
    }
    int queryfmnb(int l, int r)// b 正数的min
    {
        int k = log2(r - l + 1);
        return min(fmnb[l][k], fmnb[r - (1 << k) + 1][k]);
    }
    int querygmxa(int l, int r)// a 负数的max
    {
        int k = log2(r - l + 1);
        return max(gmxa[l][k], gmxa[r - (1 << k) + 1][k]);
    }
    int querygmna(int l, int r)// a 负数的min
    {
        int k = log2(r - l + 1);
        return min(gmna[l][k], gmna[r - (1 << k) + 1][k]);
    }
    int querygmxb(int l, int r)// b 负数的max
    {
        int k = log2(r - l + 1);
        return max(gmxb[l][k], gmxb[r - (1 << k) + 1][k]);
    }
    int querygmnb(int l, int r)// b 负数的min
    {
        int k = log2(r - l + 1);
        return min(gmnb[l][k], gmnb[r - (1 << k) + 1][k]);
    }
    void debug(int l1, int r1, int l2, int r2)
    {
        cout << queryfmxa(l1, r1) << " " << queryfmna(l1, r1) << " " << querygmxa(l1, r1) << " " << querygmna(l1, r1) << "\n";
        cout << queryfmxb(l2, r2) << " " << queryfmnb(l2, r2) << " " << querygmxb(l2, r2) << " " << querygmnb(l2, r2) << "\n"; 
    }
    int main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);
        cin >> n >> m >> q;
        for (int i = 1; i <= n; i++) cin >> a[i];
        for (int i = 1; i <= m; i++) cin >> b[i];
        init();
        
        while (q--)
        {
            int l1, r1, l2, r2;
            cin >> l1 >> r1 >> l2 >> r2;
            ll resfmxa = queryfmxa(l1, r1);
            ll resfmna = queryfmna(l1, r1);
            ll resgmxa = querygmxa(l1, r1);
            ll resgmna = querygmna(l1, r1);
            ll resfmxb = queryfmxb(l2, r2);
            ll resfmnb = queryfmnb(l2, r2);
            ll resgmxb = querygmxb(l2, r2);
            ll resgmnb = querygmnb(l2, r2);
            // debug(l1, r1, l2, r2);
            ll ans = -2e18;
            if (resfmxa != -1e9) // a在这一段区间有正数
            {
                if (resgmnb != 1e9) // b在这一段区间有负数,选择最小的负数
                {
                    ans = max(ans, resfmxa * resgmnb);
                    ans = max(ans, resfmna * resgmnb);
                }
                else // b没有负数,则选择正数最小的
                {
                    ans = max(ans, resfmxa * resfmnb);
                    ans = max(ans, resfmna * resfmnb);
                }
            }
            if (resgmxa != -1e9) // a在这一段区间有负数
            {
                if (resfmxb != -1e9) // b在这一段有正数,选择最大的正数
                {
                    ans = max(ans, resgmxa * resfmxb);
                    ans = max(ans, resgmna * resfmxb);
                }
                else // b没有正数
                {
                    ans = max(ans, resgmxa * resgmxb);
                    ans = max(ans, resgmna * resgmxb);
                }
            }
            cout << ans << "\n";
        }
        return 0;
    }
    

    代码长可以使用函数优化

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int N = 1e5 + 5;
    ll n, m, a[N], b[N], q;
    ll fmxa[N][17], fmna[N][17], gmxa[N][17], gmna[N][17];
    ll fmxb[N][17], fmnb[N][17], gmxb[N][17], gmnb[N][17];
    void init(ll f[][17], int op, int type, ll a[], int n) 
    {
        for (int i = 1; i <= n; i++)
        {
            if (a[i] >= 0)
            {
                if (op == 1) f[i][0] = a[i];
                else
                {
                    if (type == 1) f[i][0] = -1e9;
                    else f[i][0] = 1e9;
                }
            }
            else
            {
                if (op == 1)
                {
                    if (type == 1) f[i][0] = -1e9;
                    else f[i][0] = 1e9;
                }
                else f[i][0] = a[i];
            }
        }
        for (int j = 1; (1 << j) <= n; j++)
        {
            for (int i = 1; i + (1 << j) - 1 <= n; i++)
            {
                if (type == 1) f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
                else f[i][j] = min(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
            }
        }
    }
    ll query(int l, int r, ll f[][17], int op)
    {
        int k = log2(r - l + 1);
        if (op == 1) return min(f[l][k], f[r - (1 << k) + 1][k]);
        else return max(f[l][k], f[r - (1 << k) + 1][k]);
    }
    int main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);
        cin >> n >> m >> q;
        for (int i = 1; i <= n; i++) cin >> a[i];
        for (int i = 1; i <= m; i++) cin >> b[i];
        init(fmxa, 1, 1, a, n);
        init(fmna, 1, 2, a, n);
        init(fmxb, 1, 1, b, m);
        init(fmnb, 1, 2, b, m);
        init(gmxa, 2, 1, a, n);
        init(gmna, 2, 2, a, n);
        init(gmxb, 2, 1, b, m);
        init(gmnb, 2, 2, b, m);
        while (q--)
        {
            int l1, r1, l2, r2;
            cin >> l1 >> r1 >> l2 >> r2;
            ll resfmxa = query(l1, r1, fmxa, 2); // a数组非负数的max
            ll resfmna = query(l1, r1, fmna, 1); // a数组非负数的min
            ll resgmxa = query(l1, r1, gmxa, 2); // a数组负数的max
            ll resgmna = query(l1, r1, gmna, 1); // a数组负数的min
            ll resfmxb = query(l2, r2, fmxb, 2);
            ll resfmnb = query(l2, r2, fmnb, 1);
            ll resgmxb = query(l2, r2, gmxb, 2);
            ll resgmnb = query(l2, r2, gmnb, 1);
            ll ans = -2e18;
            if (resfmxa != -1e9) // a在这一段区间有正数
            {
                if (resgmnb != 1e9) // b在这一段区间有负数,选择最小的负数
                {
                    ans = max(ans, resfmxa * resgmnb);
                    ans = max(ans, resfmna * resgmnb);
                }
                else // b没有负数,则选择正数最小的
                {
                    ans = max(ans, resfmxa * resfmnb);
                    ans = max(ans, resfmna * resfmnb);
                }
            }
            if (resgmxa != -1e9) // a在这一段区间有负数
            {
                if (resfmxb != -1e9) // b在这一段有正数,选择最大的正数
                {
                    ans = max(ans, resgmxa * resfmxb);
                    ans = max(ans, resgmna * resfmxb);
                }
                else // b没有正数
                {
                    ans = max(ans, resgmxa * resgmxb);
                    ans = max(ans, resgmna * resgmxb);
                }
            }
            cout << ans << "\n";
        }
        return 0;
    }
    
    • 1

    [CSP-S 2022] 策略游戏(game)

    信息

    ID
    2040
    时间
    1000ms
    内存
    256MiB
    难度
    2
    标签
    递交数
    51
    已通过
    34
    上传者