AtCoder Beginner Contest 365 A~E

A.Leap Year(思维)

题意:

给你一个介于 1583 1583 1583 2023 2023 2023之间的整数 Y Y Y

求公历 Y Y Y年的天数。

在给定的范围内, Y Y Y年的天数如下:

  • 如果 Y Y Y不是 4 4 4的倍数,则为 365 365 365天;
  • 如果 Y Y Y 4 4 4的倍数,但不是 100 100 100的倍数,则为 366 366 366天;
  • 如果 Y Y Y 100 100 100的倍数,但不是 400 400 400的倍数,则为 365 365 365天;
  • 如果 Y Y Y 400 400 400的倍数,则为 366 366 366天。

分析:

判断年份是否为闰年。

  • 如果 n n n不能被 4 4 4整除,那么不是闰年。
  • 如果 n n n可以被 400 400 400整除,那么是闰年。
  • 如果 n n n不可以被 100 100 100整除但是可以被 4 4 4整除,那么是闰年。

否则就不是闰年。使用if-else语句判断即可。

代码:

#include<bits/stdc++.h>

using namespace std;

int main() {
    int n;
    cin >> n;
    if (n % 4 != 0) {
        cout << 365 << endl;
    } else if (n % 400 == 0) {
        cout << 366 << endl;
    } else if ((n % 100 != 0) && n % 4 == 0) {
        cout << 366 << endl;
    } else {
        cout << 365 << endl;
    }
    return 0;
}

B.Second Best(模拟)

题意:

给你一个长度为 N N N的整数序列 A = ( A 1 , … , A N ) A=(A_1,\ldots,A_N) A=(A1,,AN)。这里的 A 1 , A 2 , … , A N A_1,A_2,\ldots,A_N A1,A2,,AN都是不同的。

A A A中,哪个元素是第二大元素?

分析:

按照题意,使用mappair或结构体对元素进行排序即可。

代码:

#include<bits/stdc++.h>

using namespace std;
const int N = 1000100;

struct s {
    int x, id;

    bool operator<(const s &r) const {
        return x > r.x;
    }
} a[N];

int main() {
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        cin >> a[i].x;
        a[i].id = i;
    }
    sort(a + 1, a + n + 1);
    cout << a[2].id << endl;
    return 0;
}

C.Transportation Expenses(二分答案)

题意:

N N N人参加一项活动,第 i i i个人的交通费用是 A i A_i Ai日元。

活动组织者高桥决定设定交通补贴的最高限额为 x x x。第 i i i个人的补贴为 min ⁡ ( x , A i ) \min(x,A_i) min(x,Ai)日元。这里, x x x必须是一个非负整数。

高桥的预算为 M M M日元,他希望所有 N N N人的交通补贴总额最多为 M M M日元,那么补贴限额 x x x的最大可能值是多少?

如果补贴限额可以无限大,输出infinite

分析:

本题我们分情况讨论,首先考虑答案为无限大的情况。对于这种情况可以先计算序列的总和和 M M M比较,如果这个都小于等于 M M M,那么肯定答案是无穷大。

对于不是无穷大的情况,考虑尝试枚举一个 x x x,然后对于每一个 x x x判断是否满足题目条件,然后记录最大的 x x x,时间复杂度 O ( N M ) O(NM) O(NM)

x x x的枚举我们采用二分,然后来判断,题目要求 x x x的最大值,可以发现若此时的 x x x为最大,那么对于每一个 k ≤ x k\le x kx都可以满足题条件,而对于每一个 k ≥ x k\ge x kx都不能满足题目条件,满足单调性。

代码:

#include<bits/stdc++.h>

typedef long long LL;
using namespace std;
const int N = 200005;
LL n, m, a[N], ans = -1e17;

bool check(LL x) {
    LL res = 0;
    for (int i = 1; i <= n; i++)
        res += min(a[i], x);
    return (res <= m);
}

int main() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    if (check(1e17)) {
        cout << "infinite" << endl;
        return 0;
    }
    LL l = 0, r = m;
    while (l <= r) {
        LL mid = (l + r) >> 1;
        if (check(mid)) {
            ans = mid;
            l = mid + 1;
        } else
            r = mid - 1;
    }
    cout << ans << endl;
    return 0;
}

D.AtCoder Janken 3(动态规划)

题意:

高桥和青木玩了 N N N次剪刀石头布。注:在这个游戏中,石头赢剪刀,剪刀赢布,布赢石头。

青木的动作由长度为 N N N的字符串 S S S表示,字符串由"R"、"P"和"S"组成。 S S S中的第 i i i个字符表示青木在第 i i i个对局中的出招:“R"表示"石头”,“P"表示"布”,“S"表示"剪刀”。

高桥的出招满足以下条件:

  • 高桥从未输给过青木。
  • 对于 i = 1 , 2 , … , N − 1 i=1,2,\ldots,N-1 i=1,2,,N1,高桥在第 i i i场对局中的出招与他在第 ( i + 1 ) (i+1) (i+1)场对局中的出招不同。

确定高桥可能赢得的最大对局数。

可以保证存在一个满足上述条件的高桥出招顺序。

分析:

因为相邻两场对局出招不同,发现之前的对局存在后效性,考虑动态规划。

d p i , [ 0 / 1 / 2 ] dp_{i,[0/1/2]} dpi,[0/1/2]表示当前为第i场对局,当前出的拳是 R , P , S R,P,S R,P,S,最多可以赢多少局。

特殊计算一下 d p 1 , [ 0 / 1 / 2 ] dp_{1,[0/1/2]} dp1,[0/1/2] d p i , j dp_{i,j} dpi,j的值可以通过 d p i − 1 , k dp_{i-1,k} dpi1,k转移来当且仅当 k ≠ j k\neq j k=j,对于会输的出招直接赋值为一个极小值,取一个最大值然后增加对答案的贡献即可。

代码:

#include<bits/stdc++.h>

using namespace std;
const int N = 1000100;
const int MIN_INF = -2e9;
int n;
int dp[N][3];

int main() {
    cin >> n;
    string s;
    cin >> s;
    s = ' ' + s;
    if (s[1] == 'R') {
        dp[1][0] = 0;
        dp[1][1] = 1;
        dp[1][2] = MIN_INF;
    } else if (s[1] == 'P') {
        dp[1][0] = MIN_INF;
        dp[1][1] = 0;
        dp[1][2] = 1;
    } else {
        dp[1][0] = 1;
        dp[1][1] = MIN_INF;
        dp[1][2] = 0;
    }
    for (int i = 2; i <= n; ++i) {
        if (s[i] == 'R') {
            dp[i][0] = max({dp[i - 1][1], dp[i - 1][2]});
            dp[i][1] = max({dp[i - 1][0], dp[i - 1][2]}) + 1;
            dp[i][2] = MIN_INF;
        } else if (s[i] == 'P') {
            dp[i][0] = MIN_INF;
            dp[i][1] = max({dp[i - 1][0], dp[i - 1][2]});
            dp[i][2] = max({dp[i - 1][0], dp[i - 1][1]}) + 1;
        } else {
            dp[i][0] = max({dp[i - 1][1], dp[i - 1][2]}) + 1;
            dp[i][1] = MIN_INF;
            dp[i][2] = max({dp[i - 1][0], dp[i - 1][1]});
        }
    }
    cout << max({dp[n][0], dp[n][1], dp[n][2]}) << endl;
    return 0;
}

E.Xor Sigma Problem(数学)

题意:

给你一个长度为 N N N的整数序列 A = ( A 1 , … , A N ) A=(A_1,\ldots,A_N) A=(A1,,AN)。求以下表达式的值:

∑ i = 1 N − 1 ∑ j = i + 1 N ( A i ⊕ A i + 1 ⊕ … ⊕ A j ) \displaystyle\sum_{i=1}^{N-1}\sum_{j=i+1}^N(A_i\oplus A_{i+1}\oplus\ldots\oplus A_j) i=1N1j=i+1N(AiAi+1Aj)

分析:

看到异或我们考虑拆位计算答案。设当前枚举到第 k k k位,这一位有 i i i0 j j j1,因为异或为 1 1 1要求两个异或的数互不相同,所以这一位对答案的贡献即为 i × j × 2 k i\times j\times 2^k i×j×2k

将所有位对答案的贡献累加即可。

代码:

#include<bits/stdc++.h>

typedef long long LL;
using namespace std;
const int N = 200001;
LL a[N], s[N];

int main() {
    LL n;
    cin >> n;
    for (LL i = 1; i <= n; ++i) {
        cin >> a[i];
        s[i] = a[i];
        a[i] ^= a[i - 1];
    }
    LL res = 0;
    for (LL k = 0; k < 30; ++k) {
        LL cnt = 0;
        for (LL j = 0; j <= n; ++j)
            cnt += a[j] >> k & 1;
        res += cnt * (n - cnt + 1) * (1LL << k);
    }
    for (LL i = 1; i <= n; ++i)
        res -= s[i];
    cout << res << endl;
    return 0;
}

赛后交流

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

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

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值