Atcoder Beginner Contest 331 A~F

A.Tomorrow(模拟)

题意:

有一本日历,一年有MMM个月,一个月有DDD天,现在给你一个日期,给出的形式是XXXXXX年,XXXXXX月,XXXXXX日。问这个日期后面一天是哪一天。

分析:

按照要求模拟即可。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int main() {
    int t = 1;
    while (t--) {
        int M, D;
        cin >> M >> D;
        int y, m, d;
        cin >> y >> m >> d;
        d++;
        if (d > D)
            d = 1, m++;
        if (m > M)
            m = 1, y++;
        cout << y << ' ' << m << ' ' << d << endl;
    }
    return 0;
}

B.Buy One Carton of Milk(枚举)

题意:

666个鸡蛋SSS元,888个鸡蛋MMM元,121212个鸡蛋LLL元,问至少买NNN个鸡蛋需要多少钱。

分析:

分别枚举买666个,888个,121212个一包的鸡蛋的数量,取最小值即可。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int main() {
    int n, s, m, l;
    cin >> n >> s >> m >> l;
    int ans = 1e9;
    for (int a = 0; a <= n; a++) {
        for (int b = 0; b <= n; b++) {
            for (int c = 0; c <= n; c++) {
                if (a * 6 + b * 8 + c * 12 >= n) {
                    ans = min(ans, a * s + b * m + c * l);
                }
            }
        }
    }
    cout << ans << endl;
    return 0;
}

C.Sum of Numbers Greater Than Me(后缀和)

题意:

给出一个aaa序列,对于aia_iai,问大于aia_iai的所有元素之和是多少。

分析:

因为ai≤106a_i\le10^6ai106,我们从大到小枚举iiisum[i]sum[i]sum[i]表示大于等于aia_iai的数字之和。先将aia_iai出现次数记录到sum[ai]sum[a_i]sum[ai]中。从大到小递推可得sum[i]=sum[i+1]+i∗sum[i]sum[i]=sum[i+1]+i*sum[i]sum[i]=sum[i+1]+isum[i]

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6 + 10;
LL sum[N], a[N];
int main() {
    int n;
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> a[i];
        sum[a[i]]++;
    }
    for (int i = 1000000; i >= 1; i--)
        sum[i] = sum[i + 1] + sum[i] * i;
    for (int i = 0; i < n; i++)
        cout << sum[a[i] + 1] << ' ';
    return 0;
}

D Tile Pattern(二维前缀和)

题意:

给一张109∗10910^9*10^9109109的网格图,P[i][j]P[i][j]P[i][j]表示第iii行,第jjj列格子的颜色,网格图剩下格子的颜色为P[i%n][j%n]P[i\%n][j\%n]P[i%n][j%n]。询问给出矩形左上角的坐标(A,B)(A,B)(A,B),右下角的坐标(C,D)(C,D)(C,D),输出矩形内黑格子的数量。

分析:

先预处理 n∗nn∗nnn 的范围内的二维前缀和。记以 (0,0)(0,0)(0,0) 为左上角, (x,y)(x,y)(x,y) 为右下角的黑格子的数量为 f(x,y)f(x,y)f(x,y)
对于一整个区域,我们分为四部分:

  • 左上角的 (x/n)∗(y/n)(x/n)∗(y/n)(x/n)(y/n)n∗nn∗nnn 的范围
  • 右上角的 (x/n)(x/n)(x/n)n∗(y%n)n∗(y\%n)n(y%n) 的范围
  • 左下角的 (y/n)(y/n)(y/n)n∗(x%n)n∗(x\%n)n(x%n) 的范围
  • 右下角的 1 个 (x%n)∗(y%n)(x\%n)∗(y\%n)(x%n)(y%n)的范围

由二维前缀和以及容斥原理可知:ans=f(c,d)−f(c,b−1)−f(a−1,d)+f(a−1,b−1)ans=f(c,d)−f(c,b−1)−f(a−1,d)+f(a−1,b−1)ans=f(c,d)f(c,b1)f(a1,d)+f(a1,b1)

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e3 + 10;
char mp1[N][N];
int sum[N][N];
int n, q;
LL cal(int x, int y) {
    LL res = 0;
    res += 1ll * (x / n) * (y / n) * sum[n][n];
    res += 1ll * (y / n) * sum[x % n][n];
    res += 1ll * (x / n) * sum[n][y % n];
    res += 1ll * sum[x % n][y % n];
    return res;
}
int main() {
    cin >> n >> q;
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            cin >> mp1[i][j];
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            sum[i][j] = (mp1[i - 1][j - 1] == 'B') + sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1];
        }
    }
    while (q--) {
        int a, b, c, d;
        cin >> a >> b >> c >> d;
        cout << cal(c + 1, d + 1) - cal(c + 1, b) - cal(a, d + 1) + cal(a, b) << endl;
    }
    return 0;
}

E Set Meal(数据结构)

题意:

nnn道主菜,mmm道副菜,现在要选择一种主菜一种副菜作为一种组合菜。有LLL种主菜+副菜的组合菜是不提供的。询问剩下的组合菜价值之和最高的是多少。

分析:

aaa,bbb数组从小到大排序之后,把它们的组合看成一个n∗mn*mnm 的矩阵,那么我们每次只需要取右下角这个最大的值出来,先判断可不可以选,如果可以选, 那它就是答案,否则继续将这个值左边的值和上边的值放进大根堆里继续重复即可。注意判断每个数有没有被拿过,拿过的数不要重复拿。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define PII pair<int, int>
#define x first
#define y second
int main() {
    int n, m, l;
    cin >> n >> m >> l;
    vector<PII> a(n), b(m);
    for (int i = 0; i < n; i++) {
        cin >> a[i].x;
        a[i].y = i;
    }
    for (int i = 0; i < m; i++) {
        cin >> b[i].x;
        b[i].y = i;
    }
    sort(a.begin(), a.end());
    sort(b.begin(), b.end());
    set<PII> ban;
    while (l--) {
        int c, d;
        cin >> c >> d;
        ban.insert({c - 1, d - 1});
    }
    priority_queue<tuple<int, int, int>> q;
    set<PII> vis;
    q.push({a[n - 1].x + b[m - 1].x, n - 1, m - 1});
    vis.insert({n - 1, m - 1});
    while (!q.empty()) {
        auto [v, i, j] = q.top();
        q.pop();
        if (!ban.count({a[i].y, b[j].y})) {
            cout << v << '\n';
            return 0;
        }
        if (i - 1 >= 0 && !vis.count({i - 1, j})) {
            q.push({a[i - 1].x + b[j].x, i - 1, j});
            vis.insert({i - 1, j});
        }
        if (j - 1 >= 0 && !vis.count({i, j - 1})) {
            q.push({a[i].x + b[j - 1].x, i, j - 1});
            vis.insert({i, j - 1});
        }
    }
    return 0;
}

F Palindrome Query(数据结构+哈希)

题意:

给出一个长度为nnn的字符串sss,第一种操作:修改s[x]=cs[x]=cs[x]=c,第二种操作:判断s[l,r]s[l,r]s[l,r]是不是回文串。

分析:

用树状数组维护字符串的正序哈希值和逆序哈希值,修改操作相当于在树状数组中先求出删去一个字母的哈希值,再计算加上这个字母的哈希值。判断回文操作只要求出[l,r][l,r][l,r]的正序哈希值和逆序哈希值,判断是否相等即可。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define lowbit(x) (x & (-x))
const int modd = 1e9 + 7;
LL n, q, pw[1000005], t1[1000005], t2[1000005];
string s;
LL binpow(LL a, LL b, LL m) {
    a %= m;
    LL res = 1;
    while (b > 0) {
        if (b & 1)
            res = res * a % m;
        a = a * a % m;
        b >>= 1;
    }
    return res;
}
void ins(LL x, char e) { //插入
    for (int i = x; i <= n; i += lowbit(i))
        t1[i] = (t1[i] + (e - 'a') * pw[x - 1] % modd) % modd;
    for (int i = x; i <= n; i += lowbit(i))
        t2[i] = (t2[i] + (e - 'a') * pw[n - x] % modd) % modd;
}
void upd(LL x, char e) {//更新
    for (int i = x; i <= n; i += lowbit(i))
        t1[i] = (t1[i] - (s[x] - 'a') * pw[x - 1] % modd + modd) % modd;
    for (int i = x; i <= n; i += lowbit(i))
        t2[i] = (t2[i] - (s[x] - 'a') * pw[n - x] % modd + modd) % modd;
    for (int i = x; i <= n; i += lowbit(i))
        t1[i] = (t1[i] + (e - 'a') * pw[x - 1] % modd) % modd;
    for (int i = x; i <= n; i += lowbit(i))
        t2[i] = (t2[i] + (e - 'a') * pw[n - x] % modd) % modd;
    s[x] = e;
}
LL qry(LL l, LL r) {//查询
    LL res1 = 0, res2 = 0, L = (l + r + 1) / 2, R = r;
    for (int i = R; i >= 1; i -= lowbit(i))
        res1 = (res1 + t1[i]) % modd;
    for (int i = L - 1; i >= 1; i -= lowbit(i))
        res1 = (res1 - t1[i] + modd) % modd;
    res1 = res1 * binpow(pw[L - 1], modd - 2, modd) % modd;
    L = l, R = (l + r) / 2;
    for (int i = R; i >= 1; i -= lowbit(i))
        res2 = (res2 + t2[i]) % modd;
    for (int i = L - 1; i >= 1; i -= lowbit(i))
        res2 = (res2 - t2[i] + modd) % modd;
    res2 = res2 * binpow(pw[n - R], modd - 2, modd) % modd;
    return res1 == res2;
}
void solve() {
    cin >> n >> q;
    cin >> s;
    s = ' ' + s;
    pw[0] = 1;
    for (int i = 1; i <= n; ++i)
        pw[i] = pw[i - 1] * 1331 % modd;
    for (int i = 1; i <= n; ++i)
        ins(i, s[i]);
    while (q--) {
        int op;
        cin >> op;
        if (op == 1) {
            LL x;
            cin >> x;
            char e;
            cin >> e;
            upd(x, e);
        } else {
            int l, r;
            cin >> l >> r;
            if (qry(l, r))
                cout << "Yes" << endl;
            else
                cout << "No" << endl;
        }
    }
}
int main() {
    int t;
    t = 1;
    while (t--) {
        solve();
    }
    return 0;
}

学习交流

以下为学习交流QQ群,群号: 546235402,每周题解完成后都会转发到群中,大家可以加群一起交流做题思路,分享做题技巧,欢迎大家的加入。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值