CF#700 div2

A. Yet Another String Game

按照题意模拟即可。

B. The Great Hero

除了最后一击(hero可以只剩很少的血量),其他的伤害都需要老老实实互换。因此贪心的选择攻击力最大的怪兽放到最后打即可。

#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 5;
struct node
{
    int a, b;
    bool operator<(const node temp) const
    {
        return a < temp.a;
    }
} s[N];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);
    int t;
    cin >> t;
    while (t--)
    {
        long long A, B, n;
        cin >> A >> B >> n;
        for (int i = 1; i <= n; i++)
            cin >> s[i].a;
        for (int i = 1; i <= n; i++)
            cin >> s[i].b;
        sort(s + 1, s + 1 + n);
        bool flag = 1;
        for (int i = 1; i <= n; i++)
        {
            long long num = s[i].b / A + (s[i].b % A ? 1 : 0);
            if (s[i].a * (num - 1) >= B)
                flag = 0;
            else
                B -= s[i].a * num;
        }
        cout << (flag ? "YES" : "NO") << endl;
    }
    return 0;
}

C. Searching Local Minimum

CF交互经典二分。

特判一下corner, 二分出mid之后,查询mid-1,mid,mid+1,三个值的相对大小有以下几种情况:

  • 123。令r=mid-1,因为有1<2 ,那么在mid的左侧一定存在一个解。
  • 132。令r=mid-1,因为有1<3 ,那么在mid的左侧一定存在一个解。
  • 213。直接输出mid。
  • 312。直接输出mid。
  • 321。令l=mid+1,因为有1<2 ,那么在mid的右侧一定存在一个解。
  • 231。令l=mid+1,因为有1<3 ,那么在mid的右侧一定存在一个解。
#include <bits/stdc++.h>
using namespace std;

const int N = 1e5;
int a[N];

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);

    int n;
    cin >> n;

    if (n == 1)
    {
        cout << "! " << 1 << endl;
        return 0;
    }
    else if (n == 2)
    {
        cout << "? " << 1 << endl;
        cout.flush();
        cin >> a[1];
        cout << "? " << 2 << endl;
        cin >> a[2];
        cout.flush();
        cout << "! " << (a[1] < a[2] ? 1 : 2) << endl;
        cout.flush();
        return 0;
    }

    cout << "? " << 1 << endl;
    cout.flush();
    cin >> a[1];
    cout << "? " << 2 << endl;
    cout.flush();
    cin >> a[2];
    if (a[1] < a[2])
    {
        cout << "! " << 1 << endl;
        return 0;
    }

    cout << "? " << n << endl;
    cout.flush();
    cin >> a[n];
    cout << "? " << n - 1 << endl;
    cout.flush();
    cin >> a[n - 1];
    if (a[n] < a[n - 1])
    {
        cout << "! " << n << endl;
        return 0;
    }

    int l = 2, r = n - 1;
    while (l <= r)
    {
        int mid = l + r >> 1, res1, res2, res3;
        cout << "? " << mid - 1 << endl;
        cout.flush();
        cin >> res1;
        cout << "? " << mid << endl;
        cout.flush();
        cin >> res2;
        cout << "? " << mid + 1 << endl;
        cout.flush();
        cin >> res3;

        if (res2 < res1 && res2 < res3)
        {
            cout << "! " << mid << endl;
            cout.flush();
            return 0;
        }
        if (res1 < res2)
            r = mid - 1;
        else
            l = mid + 1;
    }

    return 0;
}

D1. Painting the Array I

贪心。
显然,当前考虑的元素 a i a_i ai只和之前已经分成的两个数组的最后一个元素有关。

记数组 1 1 1的最后一个元素为 V 1 V1 V1
记数组 2 2 2的最后一个元素为 V 2 V2 V2

考虑 a i a_i ai时,若

  • V 1 = V 2 = a i V1=V2=a_i V1=V2=ai,那么 a i a_i ai压入哪个数组都一样。
  • V 1 = a i V1=a_i V1=ai a i a_i ai需要压入数组 2 2 2这样做肯定不会比压入数组 1 1 1更劣,如果将 a i a_i ai压入数组 1 1 1,当前就会立即失去一个贡献,反之,只是“可能在未来”会失去一个贡献
  • V 2 = a i V2=a_i V2=ai,同上, a i a_i ai需要压入数组 1 1 1
  • V 2 ≠ a i V2 \neq a_i V2=ai V 1 ≠ a i V1\neq a_i V1=ai,在当前看, a i a_i ai压入哪个数组都一样,这时候就可以考虑能不能使“未来”的贡献更大(也即使用 a i a_i ai增加一个贡献),显然只有当 a i + 1 a_{i+1} ai+1 等于 V 1 V1 V1 V 2 V2 V2时,可以用 a i {a_i} ai隔开他们来增加(避免减少)一个贡献。

最后对两数组计算贡献即可。

#include <bits/stdc++.h>
using namespace std;

const int N = 1e5;
int a[N];

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);

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

    vector<int> v1, v2;
    v1.emplace_back(-1);
    v2.emplace_back(-1);
    a[n + 1] = -1;
    for (int i = 1; i <= n; i++)
    {
        if (a[i] != v1.back() && a[i] != v2.back())
        {
            if (v1.back() == a[i + 1])
                v1.emplace_back(a[i]);
            else
                v2.emplace_back(a[i]);
        }
        else if (a[i] != v1.back())
            v1.emplace_back(a[i]);
        else
            v2.emplace_back(a[i]);
    }
    int ans = 0, pre = -1;
    for (auto it : v1)
    {
        if (it == pre)
            continue;
        else
            ans++, pre = it;
    }
    pre = -1;
    for (auto it : v2)
    {
        if (it == pre)
            continue;
        else
            ans++, pre = it;
    }
    cout << ans << endl;
    return 0;
}

D2. Painting the Array II

两个题虽然背景差不多,但是贪心的方向还有略有不同。

同D1,我们

记数组 1 1 1的最后一个元素为 V 1 V1 V1
记数组 2 2 2的最后一个元素为 V 2 V2 V2

考虑 a i a_i ai时,若

  • V 1 = V 2 = a i V1=V2=a_i V1=V2=ai,那么 a i a_i ai压入哪个数组都一样。
  • V 1 = a i V1=a_i V1=ai a i a_i ai显然需要压入数组 1 1 1
  • V 2 = a i V2=a_i V2=ai a i a_i ai显然需要压入数组 2 2 2
  • V 2 ≠ a i V2 \neq a_i V2=ai V 1 ≠ a i V1\neq a_i V1=ai,在当前看, a i a_i ai压入哪个数组都一样,这时候就可以考虑能不能用 a i a_i ai使“未来”的贡献更小,不同于D1,这里需要考虑的“未来”包含的元素不仅仅是 a i + 1 a_{i+1} ai+1,而是后面的所有元素。我们考虑,在 a i a_i ai之后,更快出现的是 V 1 V1 V1还是 V 2 V2 V2,如果是 V 1 V1 V1,那么就将 a i a_i ai压入数组 2 2 2,避免 a i a_i ai隔开两个相同的数,反之亦然。
#include <bits/stdc++.h>
using namespace std;

const int N = 1e5;
int a[N];

map<int, deque<int>> mp;

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);

    int n;
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    for (int i = 1; i <= n; i++)
        mp[a[i]].push_back(i);
    for (int i = 1; i <= n + 1; i++)
        mp[i].push_back(0x3f3f3f3f);
    //压入一个无穷,表示后面该数不会再出现
    vector<int> v1, v2;
    v1.emplace_back(-1);
    v2.emplace_back(-1);
    mp[-1].push_back(0x3f3f3f3f);
    for (int i = 1; i <= n; i++)
    {
        if (a[i] != v1.back() && a[i] != v2.back())
        {
            if (mp[v1.back()].front() < mp[v2.back()].front())
                v2.emplace_back(a[i]);
            else
                v1.emplace_back(a[i]);
        }
        else if (a[i] == v1.back())
            v1.emplace_back(a[i]);
        else
            v2.emplace_back(a[i]);
        mp[a[i]].pop_front();
    }

    int ans = 0, pre = -1;
    for (auto it : v1)
    {
        if (it == pre)
            continue;
        else
            ans++, pre = it;
    }
    pre = -1;
    for (auto it : v2)
    {
        if (it == pre)
            continue;
        else
            ans++, pre = it;
    }
    cout << ans << endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hesorchen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值