Codeforces Round 957 (Div. 3) A~G

A.Only Pluses (枚举)

题意:

给出三个整数 a a a b b b c c c 可以执行以下操作最多 5 5 5 次。

  • 挑选其中一个整数;
  • 将其增加 1 1 1

通过这些操作可以实现的 a × b × c a \times b \times c a×b×c 的最大值是多少?

分析:

枚举 a , b , c a,b,c a,b,c三个数在操作之后的值即可。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define endl '\n'
#define PII pair<LL, LL>
const int maxn = 805;
const int INF = 1e9;
const int mod = 998244353;
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int T;
    cin >> T;
    while (T--)
    {
        int a, b, c;
        cin >> a >> b >> c;
        int ans = a * b * c;
        for (int i = a; i <= a + 5; i++)
        {
            for (int j = b; j <= b + 5; j++)
            {
                for (int k = c; k <= c + 5; k++)
                {
                    if (i + j + k - (a + b + c) <= 5)
                        ans = max(ans, i * j * k);
                }
            }
        }
        cout << ans << endl;
    }
    return 0;
}

B.Angry Monk (模拟)

题意:

给出一个数组,每次操作可以将数组中的一个数 x x x分成 x − 1 x-1 x1 1 1 1,或者将一个数 x x x和一个 1 1 1合并,问最少多少次操作可以将数组中所有数合并成一个。

分析:

我们从小到大将除了最大值的每个数字 x x x分成 x x x 1 1 1,再将他们全都合并到最大的数字上,每个数字的贡献是 2 × x − 1 2 \times x-1 2×x1

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define endl '\n'
#define PII pair<LL, LL>
const int maxn = 805;
const int INF = 1e9;
const int mod = 998244353;
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int T;
    cin >> T;
    while (T--)
    {
        int n, k, mx = 0;
        cin >> n >> k;
        int ans = 0;
        for (int i = 1; i <= k; i++)
        {
            int tmp;
            cin >> tmp;
            mx = max(mx, tmp);
            ans += 2 * tmp - 1;
        }
        cout << ans - 2 * mx + 1 << endl;
    }
    return 0;
}

C. Gorilla and Permutation (贪心)

题意:

给出三个数字 n n n m m m k k k。他们决定构造一个长度为 n n n 的排列。

对于该排列, g ( i ) g(i) g(i) 是长度为 i i i 的前缀上排列中所有不大于 m m m 的数字之和。其中 f ( i ) f(i) f(i) 是长度为 i i i 的前缀上排列中所有不小于 k k k 的数字之和。长度为 i i i 的前缀是由原始数组的前 i i i 个元素组成的子数组。

例如,如果 n = 5 n = 5 n=5 m = 2 m = 2 m=2 k = 5 k = 5 k=5 ,且排列为 [ 5 , 3 , 4 , 1 , 2 ] [5, 3, 4, 1, 2] [5,3,4,1,2] ,则:

  • f ( 1 ) = 5 f(1) = 5 f(1)=5 ,因为 5 ≥ 5 5 \ge 5 55 g ( 1 ) = 0 g(1) = 0 g(1)=0 ,因为 5 > 2 5 > 2 5>2
  • f ( 2 ) = 5 f(2) = 5 f(2)=5 ,因为 3 < 5 3 < 5 3<5 g ( 2 ) = 0 g(2) = 0 g(2)=0 ,因为 3 > 2 3 > 2 3>2
  • f ( 3 ) = 5 f(3) = 5 f(3)=5 ,因为 4 < 5 4 < 5 4<5 g ( 3 ) = 0 g(3) = 0 g(3)=0 ,因为 4 > 2 4 > 2 4>2
  • f ( 4 ) = 5 f(4) = 5 f(4)=5 ,因为 1 < 5 1 < 5 1<5 g ( 4 ) = 1 g(4) = 1 g(4)=1 ,因为 1 ≤ 2 1 \le 2 12
  • f ( 5 ) = 5 f(5) = 5 f(5)=5 ,因为 2 < 5 2 < 5 2<5 g ( 5 ) = 1 + 2 = 3 g(5) = 1 + 2 = 3 g(5)=1+2=3 ,因为 2 ≤ 2 2 \le 2 22

帮助他们找到一个使 ( ∑ i = 1 n f ( i ) − ∑ i = 1 n g ( i ) ) \left(\sum_{i=1}^n f(i) - \sum_{i=1}^n g(i)\right) (i=1nf(i)i=1ng(i)) 的值最大化的排列。

分析:

我们贪心的考虑这个问题,最优解为:让不超过 m m m的数尽量靠后,不小于 k k k的数字尽量靠前进行构造即可。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define endl '\n'
#define PII pair<LL, LL>
const int maxn = 3e5 + 5;
const int INF = 1e9;
const int mod = 998244353;
int a[maxn];
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int T;
    cin >> T;
    while (T--)
    {
        int n, m, k;
        cin >> n >> m >> k;
        int l, r;
        int x = 1;
        for (int i = n - m + 1; i <= n; i++)
        {
            a[i] = x;
            x++;
        }
        x = n;
        for (int i = 1; i <= n - m; i++)
        {
            a[i] = x;
            x--;
        }
        for (int i = 1; i <= n; i++)
        {
            cout << a[i] << ' ';
        }
        cout << endl;
    }
    return 0;
}

D. Test of Love(dp)

题意:

E r n K o r ErnKor ErnKor要过河,这条河有 n n n个格子, L L L代表平台,可以跳往 [ L , L + m ] [L,L + m] [L,L+m]的任意位置, W W W代表水,每经过一格水要消耗一个体力,最开始有 k k k个体力,也就是最多经过 k k k格水, C C C代表鳄鱼,不能待在 C C C所在的格子。给定 n , m , k n,m,k n,m,k和一个代表河流的字符串,问能否到达对岸。

分析:

d p [ i ] dp[i] dp[i]表示到达第 i i i个格子需要游多少米,如果当前是陆地,就枚举往后跳了 j j j格,则有 d p [ i + j ] = d p [ j ] dp[i+j]=dp[j] dp[i+j]=dp[j],如果当前是水域,有 d p [ i + 1 ] = d p [ i ] + 1 dp[i+1]=dp[i]+1 dp[i+1]=dp[i]+1

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define endl '\n'
#define PII pair<LL, LL>
const int maxn = 3e5 + 5;
const int INF = 1e9;
const int mod = 998244353;
int a[maxn];
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int T;
    cin >> T;
    while (T--)
    {

        int n, m, k;
        cin >> n >> m >> k;
        string s;
        cin >> s;
        s = "L" + s + "L";
        vector<int> dp(n + 2, 1e9);
        dp[0] = 0;
        for (int i = 0; i <= n; i++)
        {
            if (dp[i] > k or s[i] == 'C')
                continue;
            if (s[i] == 'L')
            {
                for (int j = 1; j <= m and i + j <= n + 1; j++)
                {
                    dp[i + j] = min(dp[i + j], dp[i]);
                }
            }
            else
            {
                dp[i + 1] = min(dp[i + 1], dp[i] + 1);
            }
        }
        if (dp[n + 1] <= k)
            cout << "YES" << endl;
        else
            cout << "NO" << endl;
    }
    return 0;
}

E. Novice’s Mistake (dp)

题意:

给一个数字 n n n,求出 10000 10000 10000以内的所有对 a , b a,b a,b,能够满足 n n n复制 a a a次构成的字符串去掉末尾的 b b b个数字得到的结果和 n × a − b n \times a-b n×ab相等。

分析:

因为这个数字至多只有 6 6 6位,我们可以枚举 a a a,再从 1 ~ 6 1~6 16枚举这个数字的位数,判断由字符串得到的数字是否满足条件。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define endl '\n'
#define PII pair<LL, LL>
const int maxn = 3e5 + 5;
const int INF = 1e9;
const int mod = 998244353;
vector<PII> ans[110];
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int T;
    cin >> T;
    while (T--)
    {
        int n;
        cin >> n;
        string s = to_string(n);
        int len = s.size();
        s += s, s += s, s += s, s += s;
        for (int a = 1; a <= 1e4; a++)
        {
            int num = 0;
            for (int j = 1; j <= 6; j++)
            {
                num *= 10;
                num += s[j - 1] - 48;
                int b = a * len - j;
                if (b <= 0 || b >= 1e4)
                    continue;
                if (n * a - b == num)
                {
                    PII p;
                    p.first = a, p.second = b;
                    ans[n].push_back(p);
                }
            }
        }
        cout << ans[n].size() << endl;
        for (int i = 0; i < ans[n].size(); i++)
        {
            cout << ans[n][i].first << ' ' << ans[n][i].second << endl;
        }
    }
    return 0;
}

F. Valuable Cards (贪心)

题意:

n n n 张卡片,上面标有不同位置的价格,第 i i i 张卡片上有一个整数 a i a_i ai ,这些价格中没有一个正整数 x x x

将这些卡片分成最少数量的坏段(以便每张卡片都只属于一个段)。如果无法选择乘积等于 x x x 的卡片子集,则该段被视为坏段。将卡片分成的所有段都必须是坏段。

正式来说,如果没有索引 i 1 < i 2 < … < i k i_1 < i_2 < \ldots < i_k i1<i2<<ik 满足 l ≤ i 1 , i k ≤ r l \le i_1, i_k \le r li1,ikr a i 1 ⋅ a i 2 … ⋅ a i k = x a_{i_1} \cdot a_{i_2} \ldots \cdot a_{i_k} = x ai1ai2aik=x ,则段 ( l , r ) (l, r) (l,r) 为坏段。

请确定坏段的最小数量。

分析:

考虑到 x x x的除数不超过 100 100 100,因此考虑枚举。我们维护一个数组用于存放 x x x的除数的数组。如果 a [ i ] a[i] a[i] x x x的除数,那么就与在该数组中的元素相乘(注意不要超过 x x x,防止数据溢出),如果该数组中出现了 x x x , 那么使答案加一并清空数组,然后把 a [ i ] a[i] a[i] 加入到这个数组中,重复以上操作即可。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define endl '\n'
#define PII pair<LL, LL>
const int maxn = 3e5 + 5;
const int INF = 1e9;
const int mod = 998244353;
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int T;
    cin >> T;
    while (T--)
    {
        int n, x;
        cin >> n >> x;
        int ans = 0;
        vector<int> a(n + 1, 0);
        for (int i = 1; i <= n; i++)
            cin >> a[i];
        map<LL, LL> f;
        for (int i = 1; i <= n; i++)
        {
            if (x % a[i] == 0)
            {
                if (f.empty())
                {
                    f[a[i]]++;
                }
                else
                {
                    map<LL, LL> g;
                    for (auto y : f)
                    {
                        if (x % (y.first * a[i]) == 0)
                            g[y.first * a[i]]++;
                    }
                    for (auto y : g)
                    {
                        f[y.first] += y.second;
                    }
                    if (f.count(x))
                    {
                        ans++;
                        f.clear();
                    }
                    f[a[i]]++;
                }
            }
        }
        ans++;
        cout << ans << endl;
    }
    return 0;
}

G. Ultra-Meow (组合数)

题意:

给出一个长度为 n n n 的数组 a a a ,由数字 1 , 2 , … , n 1, 2, \ldots, n 1,2,,n 组成。

MEX ( S , k ) \text{MEX}(S, k) MEX(S,k) 为升序排列的第 k k k 个正(严格大于零)整数,该整数不存在于集合 S S S 中。将 MEOW ( a ) \text{MEOW}(a) MEOW(a) 表示为数组 a a a 的所有不同 子集 b b b MEX ( b , ∣ b ∣ + 1 ) \text{MEX}(b, |b| + 1) MEX(b,b+1) 的总和。

集合的 MEX ( S , k ) \text{MEX}(S, k) MEX(S,k) 值示例:

  • MEX ( { 3 , 2 } , 1 ) = 1 \text{MEX}(\{3,2\}, 1) = 1 MEX({3,2},1)=1 ,因为 1 1 1 是集合中不存在的第一个正整数;
  • MEX ( { 4 , 2 , 1 } , 2 ) = 5 \text{MEX}(\{4,2,1\}, 2) = 5 MEX({4,2,1},2)=5 ,因为集合中不存在的前两个正整数是 3 3 3 5 5 5
  • MEX ( { } , 4 ) = 4 \text{MEX}(\{\}, 4) = 4 MEX({},4)=4 ,因为空集中没有数字,所以其中不存在的前 4 4 4 个正整数是 1 , 2 , 3 , 4 1, 2, 3, 4 1,2,3,4

分析:

我们考虑枚举集合的大小 i i i和最后的结果 j j j,需要满足以下条件:

  • 集合中不能含有 j j j

  • [ 1 , j − 1 ] [1,j-1] [1,j1]区间内的数字需要取 ( j − i − 1 ) (j-i-1) (ji1)个。

  • 如果集合大小还没满 i i i,就在 [ j + 1 , n ] [j+1,n] [j+1,n]区间内取剩下的数字。

我们首先预处理出组合数,就可以进行计算。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define endl '\n'
#define PII pair<LL, LL>
const int INF = 1e9;
const int mod = 1e9 + 7;
template <const int T>
struct ModInt
{
    const static int mod = T;
    int x;
    ModInt(int x = 0) : x(x % mod) {}
    ModInt(long long x) : x(int(x % mod)) {}
    int val() { return x; }
    ModInt operator+(const ModInt &a) const
    {
        int x0 = x + a.x;
        return ModInt(x0 < mod ? x0 : x0 - mod);
    }
    ModInt operator-(const ModInt &a) const
    {
        int x0 = x - a.x;
        return ModInt(x0 < 0 ? x0 + mod : x0);
    }
    ModInt operator*(const ModInt &a) const { return ModInt(1LL * x * a.x % mod); }
    ModInt operator/(const ModInt &a) const { return *this * a.inv(); }
    bool operator==(const ModInt &a) const { return x == a.x; };
    bool operator!=(const ModInt &a) const { return x != a.x; };
    void operator+=(const ModInt &a)
    {
        x += a.x;
        if (x >= mod)
            x -= mod;
    }
    void operator-=(const ModInt &a)
    {
        x -= a.x;
        if (x < 0)
            x += mod;
    }
    void operator*=(const ModInt &a) { x = 1LL * x * a.x % mod; }
    void operator/=(const ModInt &a) { *this = *this / a; }
    friend ModInt operator+(int y, const ModInt &a)
    {
        int x0 = y + a.x;
        return ModInt(x0 < mod ? x0 : x0 - mod);
    }
    friend ModInt operator-(int y, const ModInt &a)
    {
        int x0 = y - a.x;
        return ModInt(x0 < 0 ? x0 + mod : x0);
    }
    friend ModInt operator*(int y, const ModInt &a) { return ModInt(1LL * y * a.x % mod); }
    friend ModInt operator/(int y, const ModInt &a) { return ModInt(y) / a; }
    friend ostream &operator<<(ostream &os, const ModInt &a) { return os << a.x; }
    friend istream &operator>>(istream &is, ModInt &t) { return is >> t.x; }

    ModInt pow(int64_t n) const
    {
        ModInt res(1), mul(x);
        while (n)
        {
            if (n & 1)
                res *= mul;
            mul *= mul;
            n >>= 1;
        }
        return res;
    }

    ModInt inv() const
    {
        int a = x, b = mod, u = 1, v = 0;
        while (b)
        {
            int t = a / b;
            a -= t * b;
            swap(a, b);
            u -= t * v;
            swap(u, v);
        }
        if (u < 0)
            u += mod;
        return u;
    }
};
using mint = ModInt<1000000007>;
const int maxn = 5005;
mint C[maxn][maxn];
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int T;
    cin >> T;
    for (int i = 0; i <= 5000; i++)
    {
        for (int j = 0; j <= i; j++)
        {
            if (!j)
            {
                C[i][j] = 1;
            }
            else
            {
                C[i][j] = C[i - 1][j - 1] + C[i - 1][j];
            }
        }
    }
    while (T--)
    {
        int n;
        cin >> n;
        mint ans = 1;
        for (int i = 1; i <= n; i++)
        {
            for (int j = i + 1; j <= 2 * i + 1; j++)
            {
                int cnt = j - i - 1;
                mint t = j * C[min(j - 1, n)][cnt];
                if (n - j < 0)
                {
                    if (cnt != i)
                    {
                        t = 0;
                    }
                }
                else
                {
                    assert(n - j >= 0 and i - cnt >= 0);
                    t *= C[n - j][i - cnt];
                }
                ans += t;
            }
        }
        cout << ans << endl;
    }
    return 0;
}

赛后交流

在比赛结束后,会在交流群中给出比赛题解,同学们可以在赛后查看题解进行补题。

群号: 704572101,赛后大家可以一起交流做题思路,分享做题技巧,欢迎大家的加入。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值