Educational Codeforces Round 90 (Rated for Div

发布时间 2023-04-05 00:43:26作者: Zeoy_kkk

Donut Shops

现在有两个超市,第一个超市的物品按件卖,每件商品的售价为\(a\)元;第二个超市的物品按箱卖,每箱有\(b\)件物品,每箱售价为\(c\)元,现在要让你买\(x\)\(y\)件商品,使得在第一个超市买\(x\)件商品的总花费比在第二个超市买\(x\)件商品的总花费严格小,同理在第二个超市买\(y\)件商品的总花费比在第一个超市买\(y\)件商品的总花费严格小,请你求出任意\(x,y\),如果不存在输出\(-1\)

题解:思维

显然我们应该先考虑无解的情况

  1. 如果我们在第一个商店买一件商品的花费都比在第二个商店买一箱的花费多,即\(a>=c\),说明我们永远不可能在第一个商店的花费比在第二个商店的花费来的小,即\(x\)无解
  2. 如果我们在第一个商店买\(b\)件商品的花费都比在第二个商店买一箱的花费来的少,即\(a*b<=c\),说明我们永远不可能在第二个超市的花费比第一个超市的花费来的少,即\(y\)无解

那么对于有解的情况,我们只需在第一个超市买1件即可严格小于第二个超市,在第二个超市买\(b\)件(\(1\)箱)即可严格小于第一个超市

#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define debug(x) cerr << #x << '=' << x << endl
#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<ll, ll> pll;
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()
{
    int a, b, c;
    cin >> a >> b >> c;
    if (a >= c)
        cout << -1 << " " << b << endl;
    else if (a * b <= c)
        cout << 1 << " " << -1 << endl;
    else
        cout << 1 << " " << b << endl;
}
signed main(void)
{
    Zeoy;
    int T = 1;
    cin >> T;
    while (T--)
    {
        solve();
    }
    return 0;
}

Maximum Sum on Even Positions

给定长度为\(n\)的数组\(a\),数组下标从\(0\)开始,我们最多可以反转一次区间\([l,r]\)中的所有元素,使得数组\(a\)中偶数位上的元素和最大,请你求出该最大值

题解:\(dp\):最大子段和 + 思维

我们经过模拟后发现,如果\([l,r]\)区间长度为偶数长度,那我们反转\([l,r]\)中的元素,实际上就是交换了该区间中的奇数位和偶数位元素,所以题目变成交换一段连续偶数长度的区间中的奇数位和偶数位,使得数组\(a\)中偶数位上的元素和最大,那么我们是不是只要求出奇数位减去偶数位的差值,对于该差值形成的一段序列,我们找到这段序列中最大子段和\(sum\),看会不会使得答案变大即可,但是因为一个奇数位置可以和两个偶数位置交换,所以存在两种情况:

  1. a[0],a[1] a[2],a[3] a[4],a[5]...
  2. a[1],a[2] a[3],a[4] a[5],a[6]...

我们只需对两种情况分别求出最大子段和\(sum\)即可

  • 我们来讲一下最大字段和的\(dp\)做法:

状态表示:\(f[i]\):以\(a_i\)作为末尾元素的连续序列的最大和

状态属性:\(MAX\)

状态转移:

  1. 该序列中只有\(a_i\)自己: \(f[i] = max(f[i],a[i])\)
  2. 序列中有多个元素,连接上一个序列,并以\(a_i\)结尾:\(f[i] = max(f[i],f[i-1]+a[i])\)
  • 我们再来说说贪心的做法:
  1. 如果\(sum < 0\),我们直接舍弃前面的连续序列
  2. 如果\(sum>=0\),说明\(a_i\)加上\(sum\)后会变大,我们保留前面的序列
#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define debug(x) cerr << #x << '=' << x << endl
#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<ll, ll> pll;
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;

int n;
int a[N];

void solve()
{
    cin >> n;
    int ans = 0;
    for (int i = 0; i < n; ++i)
    {
        cin >> a[i];
        if (i % 2 == 0)
            ans += a[i];
    }
    int sum = 0;
    vector<int> v;
    for (int i = 1; i < n; i += 2)
        v.push_back(a[i] - a[i - 1]);
    int res = -INF;
    for (auto x : v)
    {
        if (sum >= 0)
            sum += x;
        else
            sum = x;
        res = max(res, sum);
    }
    v.clear();
    sum = 0;
    for (int i = 2; i < n; i += 2)
        v.push_back(a[i - 1] - a[i]);
    for (auto x : v)
    {
        if (sum >= 0)
            sum += x;
        else
            sum = x;
        res = max(res, sum);
    }
    ans = max(ans, ans + res);
    cout << ans << endl;
}
signed main(void)
{
    Zeoy;
    int T = 1;
    cin >> T;
    while (T--)
    {
        solve();
    }
    return 0;
}

Sum of Digits

我们定义\(f(x)\)\(x\)每一位上的数字之和,让你找到最小的非负数\(x\),使得\(f(x) + f(x+1)+...+f(x+k)=n\)

\(1<=n<=150,0<=k<=9\)

题解:构造 + 打表 + \(dp\)

看到数据范围感觉可以打表暴力,我们先简单\(dp\)预处理出\(1e6\)以内的所有\(f(x)\),然后前缀和一下,分情况讨论论:

  1. \(k=0\),我们贪心构造,尽量多出现9,最后如果有多的就放在最前面,因为是要最小的\(x\)
  2. \(k = 1\),我们打表找规律
  3. \(k>=2\),利用预处理好的前缀和\(O(n)\)查询
#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define debug(x) cerr << #x << '=' << x << endl
#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<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 1e6 + 10, M = 4e5 + 10;

int n, k;
int pre[N];
void calc()
{
    for (int i = 0; i <= 1e6; ++i)
        pre[i] = pre[i / 10] + i % 10;
    for (int i = 1; i <= 1e6; ++i)
        pre[i] = pre[i - 1] + pre[i];
}

void solve()
{
    cin >> n >> k;
    if (k == 0)
    {
        int num = n / 9;
        if (n % 9)
            cout << n % 9;
        for (int i = 1; i <= num; ++i)
            cout << "9";
        cout << endl;
    }
    else if (n >= 98 && k == 1 && n % 2 == 0)
    {
        int num = n - 98;
        num /= 2;
        if (num % 9)
            cout << num % 9;
        for (int i = 1; i <= num / 9; ++i)
            cout << 9;
        cout << 999989 << endl;
    }
    else if (n >= 89 && k == 1 && n % 2 == 1)
    {
        int num = n - 89;
        num /= 2;
        if (num % 9)
            cout << num % 9;
        for (int i = 1; i <= num / 9; ++i)
            cout << 9;
        cout << 99998 << endl;
    }
    else
    {
        for (int i = 0; i <= 1e6; ++i)
        {
            if (pre[i + k] - pre[i - 1] == n)
            {
                cout << i << endl;
                return;
            }
        }
        cout << -1 << endl;
    }
}
signed main(void)
{
    Zeoy;
    int T = 1;
    cin >> T;
    calc();
    while (T--)
    {
        solve();
    }
    return 0;
}

Network Coverage

给你\(n\)个城市,这\(n\)个城市首尾相接形成一个环,已知每个城市有一定数量的家庭需要网络。同时每一座城市中有一个网络基站,每一个网络基站可以为一定数量的家庭提供网络,并且第\(i\)个网络基站只能给第\(i\)个城市和第\(i+1\)个城市的家庭提供网络(第\(n\)个网络基站可以给第\(n\)座城市和第\(1\)座城市提供网络)。

现在给你每一座城市需要网络的家庭数量\(a_i\)和每一个网络基站可以提供的最多网络数量\(b_i\),请你判断能否使得所有的家庭都获得网络,可以则输出“YES“,否则输出”NO“。

题解:二分答案 \(O(nlogn)\)

我们发现只要确定第一座城市分配的网络数量,那么后面城市的获得的网络数量就能确定,且在线性时间内得到,我们考虑枚举给第一座城市分配的网络数量,但是一定会超时,我们考虑二分,但是关于二分上下界的调节我们需要考虑:

  1. 如果我们给第一座城市分配\(mid\)数量的网络,导致\([2,n]\)中有城市打不到规定网络数量,说明给第一座城市分配的太多了,此时我们要将上限往下调整:\(r = mid - 1\)
  2. 如果\([2,n]\)中的城市都达到了规定网络数量,但是如果加上第\(n\)座城市的,第一座城市本身数量仍然达不到规定,说明给自己分配的数量少了,需要将下限往上调:\(l = mid + 1\)
  3. 如果上述情况全都符合,说明全部城市都能获得规定数量的网络
#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define debug(x) cerr << #x << '=' << x << endl
#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<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 1e6 + 10, M = 4e5 + 10;

int n;
int a[N], b[N];

int check(int mid)
{
    vector<int> v(n + 10);
    v[1] = mid;
    v[2] = b[1] - mid;
    for (int i = 2; i <= n; ++i)
    {
        if (b[i] + v[i] >= a[i])
        {
            if (i + 1 <= n)
                v[i + 1] += b[i] + min(v[i] - a[i], 0ll);
            else
                v[1] += b[i] + min(v[i] - a[i], 0ll);
        }
        else
            return 1;
    }
    if (v[1] < a[1])
        return 2;
    return 0;
}

void solve()
{
    cin >> n;
    for (int i = 1; i <= n; ++i)
        cin >> a[i];
    for (int i = 1; i <= n; ++i)
        cin >> b[i];
    int l = 0, r = b[1];
    while (l <= r)
    {
        int mid = l + r >> 1;
        int k = check(mid);
        if (k == 1)
            r = mid - 1;
        else if (k == 2)
            l = mid + 1;
        else
        {
            cout << "YES" << endl;
            return;
        }
    }
    cout << "NO" << endl;
}
signed main(void)
{
    Zeoy;
    int T = 1;
    cin >> T;
    while (T--)
    {
        solve();
    }
    return 0;
}