Atcoder Beginner Contest 331 A~F

A.Tomorrow(模拟)

题意:

有一本日历,一年有 M M M个月,一个月有 D D D天,现在给你一个日期,给出的形式是 X X XX XX年, X X XX XX月, X X XX XX日。问这个日期后面一天是哪一天。

分析:

按照要求模拟即可。

代码:

#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(枚举)

题意:

6 6 6个鸡蛋 S S S元, 8 8 8个鸡蛋 M M M元, 12 12 12个鸡蛋 L L L元,问至少买 N N N个鸡蛋需要多少钱。

分析:

分别枚举买 6 6 6个, 8 8 8个, 12 12 12个一包的鸡蛋的数量,取最小值即可。

代码:

#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(后缀和)

题意:

给出一个 a a a序列,对于 a i a_i ai,问大于 a i a_i ai的所有元素之和是多少。

分析:

因为 a i ≤ 1 0 6 a_i\le10^6 ai106,我们从大到小枚举 i i i s u m [ i ] sum[i] sum[i]表示大于等于 a i a_i ai的数字之和。先将 a i a_i ai出现次数记录到 s u m [ a i ] sum[a_i] sum[ai]中。从大到小递推可得 s u m [ i ] = s u m [ i + 1 ] + i ∗ s u m [ 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(二维前缀和)

题意:

给一张 1 0 9 ∗ 1 0 9 10^9*10^9 109109的网格图, P [ i ] [ j ] P[i][j] P[i][j]表示第 i i i行,第 j j j列格子的颜色,网格图剩下格子的颜色为 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 ∗ n n∗n nn 的范围内的二维前缀和。记以 ( 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 ∗ n n∗n nn 的范围
  • 右上角的 ( 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)的范围

由二维前缀和以及容斥原理可知: a n s = 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(数据结构)

题意:

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

分析:

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

代码:

#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(数据结构+哈希)

题意:

给出一个长度为 n n n的字符串 s s s,第一种操作:修改 s [ x ] = c s[x]=c s[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,每周题解完成后都会转发到群中,大家可以加群一起交流做题思路,分享做题技巧,欢迎大家的加入。

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值