Educational Codeforces Round 151 (Rated for Div

C. Strong Password

给定一个字符串\(s\),一个密码的长度\(m\),下界字符串\(l\)和上界字符串\(r\),上下界字符串长度均为\(m\),且字符只在0~9范围内,上界字符串的第 \(i\) 位非严格大于下界字符串的第 \(i\) 位,密码的第 \(i\) 位需要位于 \([l_i, r_i]\) 内。问是否存在一个密码不是\(s\)的子序列?

\(1 \leq m \leq 10\)

\(1 \leq |s| \leq 3\times 10^5\)

题解:贪心 + 枚举

  • 因为\(m\)的范围比较小,所以我们不妨考虑枚举密码的每一位
  • 根据题意得知,第\(i\)位密码\(ch\)必须保证在\([l_i,r_i]\)范围内
  • 因为题目给出的是子序列,所以我们一旦选定了第\(i\)位密码为\(ch\),假设\(ch\)\(s\)中存在且第一次出现的位置为\(pos\),那么第\(i+1\)位密码应该从\(s\)的第\(pos\)位之后开始搜索
  • 我们不妨设\(s\)的第\(pos\)位之后的部分字符串为\(t\)
  • 如果我们枚举到的密码在\(t\)不存在,那么说明密码一定能被构造出来
  • 如果第\(i\)位密码的所有情况在\(t\)都存在的话,我们贪心地选择\([l_i,r_i]\)第一次出现且在\(s\)中下标最大的字符作为第\(i\)位密码
#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define all(x) (x).begin(), (x).end()
#define rson id << 1 | 1
#define lson id << 1
#define int long long
#define mpk make_pair
#define endl '\n'
using namespace std;
typedef unsigned long long ULL;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<double, double> pdd;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 2e5 + 10, M = 4e5 + 10;

void solve()
{
    string s;
    cin >> s;
    int m;
    cin >> m;
    string l, r;
    cin >> l >> r;
    bool flag = false;
    int p = 0;
    for (int i = 0; i < m; ++i)
    {
        int mx = 0;
        for (char j = l[i]; j <= r[i]; ++j)
        {
            int t = s.find(j, p);
            if (t == -1)
            {
                flag = true;
                break;
            }
            mx = max(mx, t);
        }
        p = mx + 1;
        if (flag)
        {
            cout << "YES" << endl;
            return;
        }
    }
    cout << "NO" << endl;
}
signed main(void)
{
    Zeoy;
    int T = 1;
    cin >> T;
    while (T--)
    {
        solve();
    }
    return 0;
}

D. Rating System

给定对局数\(n\),以及每个对局会使得\(rating\)的变化值\(a_i\),初始\(rating\)\(0\)。问给定的低保线\(k\)(分数到\(k\)后无论\(rating\)怎么变不会低于\(k\))为多少时,\(n\)个对局后玩家的\(rating\)最高

题解:思维 + 最大后缀

  • 容易发现答案应该是前缀和\(pre_i\)中的一个,但是如果我们枚举所有的前缀和复杂度显然为\(O(n^2)\),所以我们不妨逆向思维来考虑这个问题
  • \(suf\_max_i\)为第\(i\)位之后的最大后缀,易得\(suf\_max[i] = max(suf[i+1],pre[n]-pre[i])\)
  • 我们手模发现,对于任意一个\(k = pre_i\),最终的\(rating\)\(pre_i + suf\_max_i\)
  • image-20230630130717532
  • 这样的话,时间复杂度为\(O(n)\)
#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define all(x) (x).begin(), (x).end()
#define rson id << 1 | 1
#define lson id << 1
#define int long long
#define mpk make_pair
#define endl '\n'
using namespace std;
typedef unsigned long long ULL;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<double, double> pdd;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 3e5 + 10, M = 4e5 + 10;

int n;
int a[N];
int pre[N];

void solve()
{
    cin >> n;
    for (int i = 1; i <= n; ++i)
        cin >> a[i];
    for (int i = 1; i <= n; ++i)
        pre[i] = pre[i - 1] + a[i];
    vector<int> suf_max(n + 10);
    for (int i = n; i >= 0; i--)
        suf_max[i] = max(suf_max[i + 1], pre[n] - pre[i]);
    int k = 0;
    for (int i = 1; i <= n; ++i)
    {
        if (pre[k] + suf_max[k] < pre[i] + suf_max[i])
            k = i;
    }
    cout << max(0LL, pre[k]) << endl;
}
signed main(void)
{
    Zeoy;
    int T = 1;
    cin >> T;
    while (T--)
    {
        solve();
    }
    return 0;
}
posted @ 2023-06-30 13:10  Zeoy_kkk  阅读(44)  评论(0编辑  收藏  举报