Codeforces Round 914 (Div. 2)

D1. Set To Max (Easy Version)

题意:我们给定两个长度均为n的数组a和b,我们可以进行的操作是,从a中选一段区间[l,r],将这段区间内的a[i]全部改成这段区间的最大值,问最后能否使a变成b

思路:我们想这个操作只能让小数变成大数,那么对与a[ i ]>b[ i ]的情况一定不行,其余情况我们继续分析,对于a[ i ]<b[ i ] 我们肯定要从a的两侧找到一个等于b[ i ]的a[ j ],且a[ j ]一定要为i~j的最大值,才可以让a[ i ]变为a[ j ],更重要的是,我们这样改一个区间,会不会让 i~j里面出现a[i]>b[i],

综上,我们左右两边查找距离最近且值与b[ i ]值相同的点,只要找到的元素与a[ i ]之间不存在更大的元素,且这段区间内的b[ j ] 均大于等于b[ i ] ,那么就可以完成修改,两边有一边满足即可。

#include <bits/stdc++.h>
using namespace std;
#define pi acos(-1)
#define xx first
#define yy second
#define endl "\n"
#define lowbit(x) x & (-x)
#define int long long
#define ull unsigned long long
#define pb push_back
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
#define LF(x) fixed << setprecision(x)
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define Yshanqian ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
const int N = 1e6 + 10, M = 1010, inf = 0x3f3f3f3f, mod = 1e9 + 7, P = 13331;
const double eps = 1e-8;
void solve()
{
    int n;
    cin >> n;
    vector<int> a(n + 1);
    vector<int> b(n + 1);
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    for (int i = 1; i <= n; i++)
        cin >> b[i];
    auto check = [&](int x) -> bool
    {
        if (a[x] == b[x]) // 相等一定可以
            return 1;
        if (a[x] > b[x]) // 比b[x]还大,由于只能变大故不能实现
            return 0;

        int l = x, r = x;
        bool f1 = 0, f2 = 0;

        for (int i = x - 1; i >= 1; i--) // 找左右两边等于b[x]的a[j],如果出现大于b[x]的则不行,或者b[i]<b[x]这个个上面比b[x]还大,由于只能变大故不能实现一样
        {
            if (a[i] > b[x] || b[i] < b[x])
            {
                f1 = 1;
                break;
            }
            if (a[i] == b[x])
            {
                l = i;
                break;
            }
        }

        for (int i = x + 1; i <= n; i++)
        {
            if (a[i] > b[x] || b[i] < b[x])
            {
                f2 = 1;
                break;
            }
            if (a[i] == b[x])
            {
                r = i;
                break;
            }
        }

        if (r == x)
            f2 = 1;
        if (l == x)
            f1 = 1;
        if (f1 && f2) // 两边有一边就可以实现
            return 0;
        return 1;
    };
    for (int i = 1; i <= n; i++)
    {
        if (!check(i))
        {
            cout << "NO" << endl;
            return;
        }
    }
    cout << "YES" << endl;
}
signed main()
{
    Yshanqian;
    int T;
    T = 1;
    cin >> T;
    for (int cases = 1; cases <= T; ++cases)
    {
        // cout<<"Case #"<<cases<<": ";
        solve();
    }
    return 0;
}

D2. Set To Max (Hard Version)

思路:

按照值存下标,二分找最近的L和R

ST表预处理 a区间最大值 和 b区间最小值 即可解

或者线段树区间求区间最值也可以,就是写起来有点长

#include <bits/stdc++.h>
using namespace std;
#define pi acos(-1)
#define xx first
#define yy second
#define endl "\n"
#define lowbit(x) x & (-x)
#define int long long
#define ull unsigned long long
#define pb push_back
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
#define LF(x) fixed << setprecision(x)
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define Yshanqian ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
const int N = 1e6 + 10, M = 1010, inf = 0x3f3f3f3f, mod = 1e9 + 7, P = 13331;
const double eps = 1e-8;
void solve()
{
    int n;
    cin >> n;
    vector<int> a(n + 1);
    vector<int> b(n + 1);

    for (int i = 1; i <= n; i++)
        cin >> a[i];
    for (int i = 1; i <= n; i++)
        cin >> b[i];

    vector<vector<int>> f(n + 1, vector<int>(21));
    vector<vector<int>> g(n + 1, vector<int>(21));

    auto init = [&]() -> void
    {
        for (int j = 0; j <= 20; j++)
        {
            for (int i = 1; i + (1 << j) - 1 <= n; i++)
            {
                if (!j)
                {
                    f[i][j] = a[i];
                    g[i][j] = b[i];
                }
                else
                {
                    f[i][j] = max(f[i][j - 1], f[i + (1 << j - 1)][j - 1]);
                    g[i][j] = min(g[i][j - 1], g[i + (1 << j - 1)][j - 1]);
                }
            }
        }
    };

    auto query_max = [&](int l, int r) -> int
    {
        int len = r - l + 1;
        int k = log2(len);
        return max(f[l][k], f[r - (1 << k) + 1][k]);
    };

    auto query_min = [&](int l, int r) -> int
    {
        int len = r - l + 1;
        int k = log2(len);
        return min(g[l][k], g[r - (1 << k) + 1][k]);
    };

    for (int i = 1; i <= n; i++)
    {
        if (a[i] > b[i])
        {
            cout << "NO" << endl;
            return;
        }
    }

    init();

    vector<vector<int>> p(n + 1);

    for (int i = 1; i <= n; i++)//防止L越界,存个下界
        p[i].pb(0);

    for (int i = 1; i <= n; i++)//按值存下标
        p[a[i]].pb(i);

    for (int i = 1; i <= n; i++)//防止R越界存个上界
        p[i].pb(n + 1);

    for (int i = 1; i <= n; i++)
    {
        bool ok = 0;
        int x = b[i];

        if (a[i] == b[i])
            continue;

        int R = upper_bound(p[x].begin(), p[x].end(), i) - p[x].begin();
        int L = R - 1;//由于当前的i一定不等于b[i] 所以R-1一定为左边第一个等于x的a[j]

        R = p[x][R];
        L = p[x][L];

        if (L != 0)
        {
            if (query_max(L, i) == x && query_min(L, i) == x)
            {
                ok = 1;
            }
        }

        if (R != n + 1)
        {
            if (query_max(i, R) == x && query_min(i, R) == x)
            {
                ok = 1;
            }
        }

        if (!ok)
        {
            cout << "NO" << endl;
            return;
        }

    }
    cout << "YES" << endl;
}
signed main()
{
    Yshanqian;
    int T;
    T = 1;
    cin >> T;
    for (int cases = 1; cases <= T; ++cases)
    {
        // cout<<"Case #"<<cases<<": ";
        solve();
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值