Codeforces Round #841 (Div. 2) A,B,D,补C

A. Joey Takes Money

题意:

给定 n 个整数,每次操作可以选择两个整数,获得两数之积,再构造一组 (x,y) 使得 x * y 等于两数之积,并将原来的数替换为 x, y ,求操作若干次后 n 个数的最大和。

分析:

考虑最终情况:只有一个 n 个数的乘积 k 与 n - 1 个 1 组成,sum = k + n - 1

#include <bits/stdc++.h>
#include <bits/extc++.h>
using namespace std;
using namespace __gnu_pbds;
#define mst(x, y) memset(x, y, sizeof x)
#define endl '\n'
#define INF LONG_LONG_MAX
#define x first
#define y second
#define int long long
#define Lson u << 1, l, mid
#define Rson u << 1 | 1, mid + 1, r
#define FAST ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
const int N = 200010, MOD = 1e9 + 7;
const double EPS = 1e-6;
typedef pair<int, int> PII;
typedef unordered_map<int, int> Ump;
int T;
int n;
int a[N];
void solve()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> a[i];

    int t = 1;
    for (int i = 1; i <= n; i++)
    {
        t *= a[i];
    }
    cout << (t + n - 1) * 2022 << endl;
}
signed main()
{
    FAST;
    cin >> T;
    while (T--)
        solve();
    return 0;
}

B. Kill Demodogs

题意:

在 n * n 的网格,每个格子上存在 行号 * 列号 个怪物,你从 (1, 1) 出发,只能向下和向右走,走到 (n, n) 一路上最多击杀多少怪物。

分析:

找规律即可发现:右/下交替走即可保证 sum 最大,下面处理如何求 sum :
列出式子:$$0 * 1 + 1 * 1 + 1 * 2 + 2 * 2 + 3 * 2 + 3 * 3 + ...... + n * (n - 1) + n * n$$
即:

\[1 * 1 + 2 * 3 + 3 * 5 + 4 * 7 + ...... + n * (2 * n - 1) \]

即:

\[2 * (1^2 + 2^2 + 3^2 + ...... + n^2 ) - (1 + 2 + 3 + 4 + ...... + n) \]

即:

\[2 * \frac{n * (n + 1) * (2 * n + 1)}{6} - \frac{n*(n + 1)}{2} \]

平方和
这里由于答案还要 ×2022 可以化简后直接运算或者求乘法逆元计算

#include <bits/stdc++.h>
#include <bits/extc++.h>
using namespace std;
using namespace __gnu_pbds;
#define mst(x, y) memset(x, y, sizeof x)
#define endl '\n'
#define INF LONG_LONG_MAX
#define x first
#define y second
#define int long long
#define Lson u << 1, l, mid
#define Rson u << 1 | 1, mid + 1, r
#define FAST ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
const int N = 200010, MOD = 1e9 + 7;
const double EPS = 1e-6;
typedef pair<int, int> PII;
typedef unordered_map<int, int> Ump;
int T;
int n;
int qmi(int a, int k, int p) // 求a^k mod p
{
    int res = 1 % p;
    while (k)
    {
        if (k & 1)
            res = res * a % p;
        a = a * a % p;
        k >>= 1;
    }
    return res;
}
void solve()
{
    cin >> n;
    int res = n * (n + 1) % MOD * (2 * n + 1) % MOD * qmi(6, MOD - 2, MOD) % MOD;
    res = 2 * res % MOD - (n + 1) * n % MOD * qmi(2, MOD - 2, MOD) % MOD;
    res = (res % MOD + MOD) % MOD;
    res = res * 2022 % MOD;
    cout << res << endl;
}
signed main()
{
    FAST;
    cin >> T;
    while (T--)
        solve();
    return 0;
}

D. Valiant's New Map

题意:

给定一个 n 行 m 列的矩阵,找到一个最大的数字 k ,使得在矩阵 k * k 中存在一个 的子矩阵,满足其中所有的数都大于等于 k

分析:

构造辅助矩阵,二分答案,check子矩阵的二维前缀

#include <bits/stdc++.h>
#include <bits/extc++.h>
using namespace std;
using namespace __gnu_pbds;
#define mst(x, y) memset(x, y, sizeof x)
#define endl '\n'
#define INF LONG_LONG_MAX
#define x first
#define y second
#define int long long
#define Lson u << 1, l, mid
#define Rson u << 1 | 1, mid + 1, r
#define FAST ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
const int N = 200010, MOD = 1e9 + 7;
const double EPS = 1e-6;
typedef pair<int, int> PII;
typedef unordered_map<int, int> Ump;
int T;
int n, m;
int g[3000][3000];
int s[3000][3000];
int d[3000][3000];
bool check(int mid)
{
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            if (g[i][j] >= mid)
                d[i][j] = 1;
            else
                d[i][j] = 0;

    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + d[i][j];

    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            int x = i + mid - 1, y = j + mid - 1;
            if (x > n || y > m)
                continue;
            int t = s[x][y] - s[i - 1][y] - s[x][j - 1] + s[i - 1][j - 1];
            if (t >= mid * mid)
                return true;
        }
    }
    return false;
}
void solve()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            cin >> g[i][j];

    int l = 0, r = max(n, m);
    while (l < r)
    {
        int mid = l + r + 1 >> 1;
        if (check(mid))
            l = mid;
        else
            r = mid - 1;
    }
    cout << l << endl;
}
signed main()
{
    FAST;
    cin >> T;
    while (T--)
        solve();
    return 0;
}

C. Even Subarrays(补位运算)

ygg详解链接
评论区解释了如何计算满足的子区间的方法

posted @ 2022-12-28 12:23  347Foricher  阅读(151)  评论(0)    收藏  举报