Codeforces Round 906 (Div. 2)

Codeforces Round 906 (Div. 2)

A. Doremy's Paint 3

解题思路:

\(a_1 + a_2 = a_2 + a_3\),所以\(a_1 = a_3\)。以此类推。所以整个序列最多出现两种不同的数字。

\(n = 2\)时,必然存在。

\(n = 3\)时,如果出现数字的种类数量小于等于2,那么必然存在。

\(n > 3\)时,若序列中只有一种数字,那么必然存在。若出现两种数字,则如果两种数字出现次数之差的绝对值小于等于1,那么必然存在。否则不存在。

代码:

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

void solve()
{
    int n;
    cin >> n;
    vector<int> v(n + 1);
    map<int, int> cnt;
    for (int i = 1; i <= n; i++)
    {
        cin >> v[i];
        cnt[v[i]]++;
    }
    if (n == 2 || cnt.size() == 1)
    {
        puts("YES");
        return;
    }
    if (n == 3)
    {
        if (cnt.size() > 2)
        {
            puts("NO");
            return;
        }
        else
        {
            puts("YES");
            return;
        }
    }
    if (cnt.size() >= 3)
    {
        puts("NO");
        return;
    }
    sort(v.begin() + 1, v.end());
    v.erase(unique(v.begin() + 1, v.end()), v.end());
    if (n & 1)
    {
        if (abs(cnt[v[1]] - cnt[v[2]]) != 1)
        {
            puts("NO");
        }
        else
        {
            puts("YES");
        }
    }
    else
    {
        if (abs(cnt[v[1]] - cnt[v[2]]) != 0)
        {
            puts("NO");
        }
        else
        {
            puts("YES");
        }
    }
}

int main()
{
    int t = 1;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

B. Qingshan Loves Strings

解题思路:

首先,判断原字符串是否符合要求。

若符合,就是操作零次。

若不符合,我们中间统计需要操作的相邻字符的特质。即,是否存在相邻的\(0\)和相邻的\(1\)

如果两种情况同时存在,我们必然无法通过插入\(t\)字符串是的字符串合法。因为字符串\(t\)在插入后,首尾字符必定会与\(0或1\)相连。当两种情况同时存在时,至少有一种情况插入后仍然会产生新的非法相邻字符对。

若只存在相邻的\(0\),那么如果字符串\(t\)的首尾都为\(1\)即可操作。

若只存在相邻的\(1\),那么如果字符串\(t\)的首尾都为\(0\)即可操作。

代码:

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

void solve()
{
    int n, m;
    cin >> n >> m;
    string s, t;
    cin >> s >> t;
    m = t.size();
    n = s.size();

    int type = 0;
    for (int i = 0; i < n - 1; i++)
    {
        if (s[i] == s[i + 1])
        {
            if (s[i] == '1' && (type < 2))
            {
                type += 1 << 1;
            }
            else if (s[i] == '0' && !(type & 1))
            {
                type += 1;
            }
        }
    }
    if (type != 0)
    {
        for (int i = 0; i < m - 1; i++)
        {
            if (t[i] == t[i + 1])
            {
                puts("NO");
                return;
            }
        }
        if (type == 3)
        {
            puts("NO");
        }
        else if (type == 2)
        {
            if (t[0] == t.back() && t[0] == '0')
            {
                puts("YES");
            }
            else
            {
                puts("NO");
            }
        }
        else if (type == 1)
        {
            if (t[0] == t.back() && t[0] == '1')
            {

                puts("YES");
            }
            else
            {
                puts("NO");
            }
        }
    }
    else
    {
        puts("YES");
    }
}

int main()
{
    int t = 1;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

C. Qingshan Loves Strings 2

解题思路:

两个指针,一个头一个尾对比。如果当前两个位置的字符不同,则符合要求,可删去两个字符,得到更短的字符串的子问题。

如果,当前两指针相同,分情况讨论:

  1. 两字符都为\(0\),那么我们只能在尾指针后面插入\(01\),然后删去两个字符,得到更短的字符串的子问题。
  2. 两字符都为\(1\),那么我们只能在头指针前面插入\(01\),然后删去两个字符,得到更短的字符串的子问题。

如果子问题和上一个问题遇到的字符串相同,说明陷入死循环,无法操作。

按题意,如果操作次数大于\(300\),同样结束。

否则,当前字符串长度为\(0\)时,操作结束。

代码:

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

void solve()
{
    int n;
    cin >> n;
    string s;
    cin >> s;
    string last = s;
    int l = 0;
    int r = n;
    vector<int> v;
    while (true)
    {
        if (s[0] == s[n - 1] && s[0] == '0')
        {
            s += "01";
            s = s.substr(1, n);
            v.push_back(r);
            r++;
            l++;
        }
        else if (s[0] == s[n - 1] && s[0] == '1')
        {
            s = "01" + s;
            s = s.substr(1, n);
            v.push_back(l);
            r++;
            l++;
        }
        else
        {
            n -= 2;
            s = s.substr(1, n);
            l++;
            r--;
        }
        if (s == last || v.size() > 300)
        {
            cout << -1 << endl;
            return;
        }
        last = s;
        if (s.size() == 0 && v.size() <= 300)
        {
            cout << v.size() << endl;
            for (auto x : v)
            {
                cout << x << ' ';
            }
            cout << endl;
            return;
        }
    }
}

int main()
{
    int t = 1;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

D. Doremy's Connecting Plan

解题思路:

\[a_i + a_j \geq i * j * c \geq (i + j) * c \]

\[a_i + a_j \geq i*c + j*c \]

如果,\(a_i < i * c\)那么必然有\(a_j \geq j * c\)

所以,能够相连的两个点,其中有一个点必然能够与\(a_1\)相连。

\[a_1 + a_i \geq i * c * 1 \]

所以,我们可以根据\(i * c - a_i\)排个序,从小到大判断是否和\(a_1\)所在连通块中的\(a_1\)相连。

时间复杂度:\(O(nlogn)\)

代码(\(O(nlogn)\):

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

void solve()
{
    ll n, c;
    cin >> n >> c;
    pair<ll, ll> v[n + 1];
    ll sum = 0;
    cin >> sum;
    for (int i = 2; i <= n; i++)
    {
        cin >> v[i].second;
        v[i].first = i;
    }
    sort(v + 2, v + n + 1, [&](pair<ll, ll> a, pair<ll, ll> b)
         { return a.first * c - a.second < b.first * c - b.second; });
    for (int i = 2; i <= n; i++)
    {
        if (sum + v[i].second >= v[i].first * c)
        {
            sum += v[i].second;
        }
        else
        {
            puts("NO");
            return;
        }
    }
    puts("YES");
}

int main()
{
    int t = 1;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

\(a_1 + a_i \geq i * c * 1\)时,其实意味着对于所有\(a_j,(j < i)\)也都可以跟\(a_1\)相连。

\[S(a_1) + a_j \geq 1 * j * c \]

因为如果能和\(i\)相连后,再于前面的点相连,意味着此时上述式子左值增大,右值减小,必然符合。

所以,我们可以直接记录一个前缀和扫过去即可。

代码\((O(n))\):

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

void solve()
{
    ll n, c;
    cin >> n >> c;
    vector<ll> a(n + 1), s(n + 1);
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        s[i] = s[i - 1] + a[i];
    }
    ll cur = 1;
    for (int i = 2; i <= n; i++)
    {
        if (s[cur] + a[i] >= i * c)
        {
            cur = i;
        }
    }
    if (cur == n)
    {
        puts("YES");
    }
    else
    {
        puts("NO");
    }
}

int main()
{
    int t = 1;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}
posted @ 2023-11-01 01:20  value0  阅读(52)  评论(0)    收藏  举报