AtCoder Beginner Contest 184题解全

AtCoder Beginner Contest 184

在这里插入图片描述
在这里插入图片描述
题目链接:https://atcoder.jp/contests/abc184/tasks

类似于牛客小白月赛,建议萌新们去体验一下,顺便复习四六级~

还是一样的,代码分成主体和头文件两部分,头文件在文末。

A - Determinant

给你一个2*2的矩阵,输出它的行列式。

著名dreemoon说过,ABCA题都是printf题。

const int MXN = 1e5 + 5;
int n, m;
int a, b, c, d;
void work() {
    a = read(), b = read(), c = read(), d = read();
    printf("%d\n", a * d - b * c);
}

B - Quizzes

给你一个长度为 n n n的字符串表示 n n n场比赛的结果,o表示胜利加一分,x表示失败减一分,0分输了不扣分,初始时有 X X X分。请输出最后得分。

著名dreemoon说过,ABCA题都是for枚举模拟题。

const int MXN = 2e5 + 5;
int n, m;
char s[MXN];
void work() {
    n = read(), m = read();
    scanf("%s", s);
    for(int i = 0; i < n; ++i) {
        if(s[i] == 'o') ++ m;
        else m = max(0, m - 1);
    }
    printf("%d\n", m);
}

C - Super Ryuma

在一个无限二维笛卡尔系中,如果你在点 ( a , b ) (a,b) (a,b),一步之类你可以移动到满足下述条件的点 ( c , d ) (c,d) (c,d)

  • a + b = c + d a+b=c+d a+b=c+d
  • a − b = c − d a-b=c-d ab=cd
  • ∣ a − c ∣ + ∣ b − d ∣ ≤ 3 |a - c| + |b - d| \le 3 ac+bd3

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rfSlUlfe-1607677880546)(D:\ACM\tmpFolder\markdown\我的推送\abc184_c.jpg)]

初始你在 ( r 1 , c 1 ) (r1,c1) (r1,c1),目的地是 ( r 2 , c 2 ) (r2,c2) (r2,c2),问最少移动次数。

1 ≤ r 1 , c 1 , r 2 , c 2 ≤ 1 0 9 1\le r1,c1,r2,c2\le 10^9 1r1,c1,r2,c2109.

思路

答案最多不超过三步。因为前两个条件保证每个点一步内能到两条垂直直线上的任意点。起点和目的点分别画出他们的两条直线,肯定会有交点,但是交点可能不是一个完整的格子,如果是完整的格子,两步内就肯定可以到达了。

所以本题只需判断两个点能否一步走到,否则看两步能否走到,否则输出三步即可。

const int MXN = 2e5 + 5;
int n, m;
class node{
    public:
    int a, b;
    void Rd() {
        a = read(), b = read();
    }
};
node A, B;
int ans;
int one_step(node A, node B) {
    if(A.a + A.b == B.a + B.b) return 1;
    if(A.a - A.b == B.a - B.b) return 2;
    if(abs(A.a - B.a) + abs(A.b - B.b) <= 3) return 3;
    return 0;
}
void work() {
    A.Rd(), B.Rd();
    if(A.a == B.a && A.b == B.b) ans == 0;
    else if(one_step(A, B)) ans = 1;
    else if((A.a + A.b) % 2 == (B.a + B.b) % 2) ans = 2;//走两次直线
    else {
        ans = 3;
        rep(i, -3, 4) {
            rep(j, -3, 4) {
                if(abs(i) + abs(j) > 3) continue;
                A.a += i, A.b += j;
                if(one_step(A, B)) ans = 2;
                A.a -= i, A.b -= j;
            }
        }
    }
    printf("%d\n", ans);
}

D - increment of coins

一个黑箱里面有三色糖果,初始时分别有 a , b , c a,b,c a,b,c个。每次等概率取出一个糖果,再额外放回去一个这种颜色的糖果。问期望次数使得某种颜色糖果个数达到100

1 ≤ a , b , c ≤ 99 , a + b + c ≥ 1 1\le a,b,c\le 99,a+b+c\ge 1 1a,b,c99,a+b+c1.

思路

推荐练习题HDU6558

d p [ a ] [ b ] [ c ] dp[a][b][c] dp[a][b][c]表示现在糖果数量状态是 ( a , b , c ) (a,b,c) (a,b,c)要达到某种糖果100个需要的期望次数。

状态转移现在只有三种,选出 a , b , c a,b,c a,b,c,概率分别是 a a + b + c , b a + b + c , c a + b + c \frac a{a+b+c},\frac b{a+b+c},\frac c{a+b+c} a+b+ca,a+b+cb,a+b+cc

d p [ a ] [ b ] [ c ] = ( a ∗ d p [ a + 1 ] [ b ] [ c ] + b ∗ d p [ a ] [ b + 1 ] [ c ] + c ∗ d p [ a ] [ b ] [ c + 1 ] ) / ( a + b + c ) + 1 dp[a][b][c] = (a * dp[a + 1][b][c] + b * dp[a][b + 1][c] + c * dp[a][b][c + 1])/(a + b + c) + 1 dp[a][b][c]=(adp[a+1][b][c]+bdp[a][b+1][c]+cdp[a][b][c+1])/(a+b+c)+1

期望 d p dp dp经典写一个递归的dfs求出或者迭代法求出。

一般都是正向推概率,反向推期望。

int a, b, c;
double dp[101][101][101];
const double eps = 1e-8;
double dfs(int a, int b, int c) {
    if(fabs(dp[a][b][c]) > eps) return dp[a][b][c];
    if(a == 100 || b == 100 || c == 100) return dp[a][b][c] = 0;
    return dp[a][b][c] = (a * dfs(a + 1, b, c) + b * dfs(a, b + 1, c) + c * dfs(a, b, c + 1))/(a + b + c) + 1;
}
void work() {
    a = read(), b = read(), c = read();
    dfs(a, b, c);
    printf("%.9f\n", dp[a][b][c]);
}
---
hdu6558代码
int n, m;
double dp[MXN];
double dfs(int p) {
    if(p >= 1000) return 100.0/n;
    if(fabs(dp[p] - 0) > 1e-9) return dp[p];
    dp[p] = (n*(p+(1000-p)*(dfs(p+20)+1))/1000.0+
        (100-n)*(1+dfs(p+15)))/100.0;
    return dp[p];
}
double dfs2(int p) {
    if(p >= 1000) return 100.0/n;
    if(fabs(dp[p] - 0) > 1e-9) return dp[p];
    dp[p] = 1 + (n*(1000-p)*(dfs2(p+20))/1000.0+
        (100-n)*(dfs2(p+15)))/100.0;
    return dp[p];
}
int main() {
    int tim = read(), cas = 0;
    while(tim --) {
        n = read();
        printf("Case %d: ", ++ cas);
        clr(dp, 0);
        dfs2(20);
        printf("%.10f\n", dp[20]);
    }
    return 0;
}

E - Third Avenue

H ∗ W H*W HW矩阵中起点S,终点G,有26种颜色传送门a,…,z,障碍物#,平地.

  • 障碍物无论如何都不能移动过去
  • 1秒内可以选择上下左右移动一步
  • 如果身处x色传送门,1秒内可以移动到任意一个同色传送门。

问最短时间从起点到达终点。永远都到不了就输出-1

1 ≤ H , W ≤ 2000 1\le H,W\le 2000 1H,W2000.

思路

BFS直接莽,暴力冲就完事了。对传送门用26vector存储起来即可。

BFS的时候枚举四个方向移动或者移动到所有可以移动到的传送门位置。

同时对移动过的点打标记,不能走到标记过的点。

注意移动过的传送门一定要及时清空,不然会TLE

const int MXN = 2e3 + 5;
int n, m;
char ar[MXN][MXN];
int vis[MXN][MXN];
vector<pii> az[26];
bool out(int a, int b) {
    return a < 1 || a > n || b < 1 || b > m || ar[a][b] == '#';
}
void work() {
    queue<pii> Q;
    n = read(), m = read();
    rep(i, 1, n + 1) {
        scanf("%s", ar[i] + 1);
        rep(j, 1, m + 1) {
            if(ar[i][j] == 'S') {
                Q.push(mk(i, j));
                vis[i][j] = 1;
            }
            if(islower(ar[i][j])) az[ar[i][j]-'a'].eb(mk(i, j));
        }
    }
    while(!Q.empty()) {
        pii u = Q.front();
        if(ar[u.fi][u.se] == 'G') break;
        Q.pop();
        rep(i, -1, 2) {
            if(i == 0) continue;
            int px = u.fi + i, py = u.se;
            if(!out(px, py) && vis[px][py] == 0) {
                vis[px][py] = vis[u.fi][u.se] + 1;
                Q.push(mk(px, py));
            }
            px = u.fi, py = u.se + i;
            if(!out(px, py) && vis[px][py] == 0) {
                vis[px][py] = vis[u.fi][u.se] + 1;
                Q.push(mk(px, py));
            }
        }
        if(islower(ar[u.fi][u.se]) && !az[ar[u.fi][u.se] - 'a'].empty()) {
            for(pii x: az[ar[u.fi][u.se] - 'a']) {
                if(vis[x.fi][x.se] == 0) {
                    vis[x.fi][x.se] = vis[u.fi][u.se] + 1;
                    Q.push(mk(x.fi, x.se));
                }
            }
            az[ar[u.fi][u.se] - 'a'].clear();
        }
    }
    if(Q.empty()) printf("-1\n");
    else printf("%d\n", vis[Q.front().fi][Q.front().se] - 1);
}

F - Programming Contest

n n n个糖果,每个糖果美味度和容量都是 a i a_i ai,有一个容量为 T T T的包裹,问可以装的糖果的美味度之和的最大值。

1 ≤ n ≤ 40 , 1 ≤ a i ≤ 1 0 9 1\le n\le 40, 1\le a_i\le 10^9 1n40,1ai109.

思路

这是一道meet in middle题目。

n n n个糖果分成两半,然后 O ( 2 20 ) O(2^{20}) O(220)枚举每一半所有组合存起来,然后排个序,双指针或者二分求一下最大值即可。

const int MXN = 1e2 + 5;
int n, m;
int ar[MXN];
int64 T, ans;
vector<int> vs, vt;
vector<int64> sum, tum;
void work() {
    n = read();
    T = read();
    for(int i = 1; i <= n; ++i) ar[i] = read();
    sort(ar + 1, ar + n + 1);
    for(int i = 1; i <= n; ++i) {
        if(i <= n / 2) vs.eb(ar[i]);
        else vt.eb(ar[i]);
    }
    n = vs.size();
    m = 1 << n;
    for(int i = 1; i < m; ++i) {
        int64 res = 0;
        for(int j = 0; j < n; ++j) 
            if(i & (1 << j)) res += vs[j];
        if(res <= T) ans = max(ans, res);
        if(ans == T) break;
        if(res < T) sum.eb(res);
    }
    n = vt.size();
    m = 1 << n;
    for(int i = 1; i < m; ++i) {
        int64 res = 0;
        for(int j = 0; j < n; ++j) 
            if(i & (1 << j)) res += vt[j];
        if(res <= T) ans = max(ans, res);
        if(ans == T) break;
        if(res < T) tum.eb(res);
    }
    sort(all(tum));
    for(int x: sum) {
        if(x > T) continue;
        int p = upper_bound(all(tum), T - x) - tum.begin();
        if(p != 0) ans = max(ans, tum[p - 1] + x);
        if(ans == T) break;
    }
    printf("%lld\n", ans);
}

头文件

#include <bits/stdc++.h>
#define fi first
#define se second
#define o2(x) (x) * (x)
#define mk make_pair
#define eb emplace_back
#define SZ(x) ((int)(x).size())
#define all(x) (x).begin(), (x).end()
#define clr(a, b) memset((a), (b), sizeof((a)))
#define rep(i, s, t) for(register int i = (s), LIM=(t); i < LIM; ++i)
#define per(i, s, t) for(register int i = (s), LIM=(t); i >= LIM; --i)
#define GKD std::ios::sync_with_stdio(false);cin.tie(0)
#define my_unique(x) sort(all(x)), x.erase(unique(all(x)), x.end())
using namespace std;
typedef long long LL;
typedef long long int64;
typedef unsigned long long uint64;
typedef pair<int, int> pii;
// mt19937 rng(time(NULL));//std::clock()
// mt19937_64 rng64(chrono::steady_clock::now().time_since_epoch().count());
// shuffle(arr, arr + n, rng64);
inline int64 read() {
    int64 x = 0;int las = 0;char ch = getchar();
    while (ch < '0' || ch > '9') las |= (ch == '-'), ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch =
    getchar(); return x = las ? -x : x;
}
inline void write(int64 x, bool las = true) {
    if (x == 0) {putchar('0'); if(las)putchar('\n');else putchar(' ');return;}
    if (x < 0) {putchar('-');x = -x;}
    static char s[23];
    int l = 0;
    while (x != 0)s[l++] = x % 10 + 48, x /= 10;
    while (l)putchar(s[--l]);
    if(las)putchar('\n');else putchar(' ');
}
int lowbit(int x) { return x & (-x); }
template <class T>
T big(const T &a1, const T &a2) {return a1 > a2 ? a1 : a2;}
template <class T>
T sml(const T &a1, const T &a2) {return a1 < a2 ? a1 : a2;}
template <typename T, typename... R>
T big(const T &las, const R &... r) {return big(las, big(r...));}
template <typename T, typename... R>
T sml(const T &las, const R &... r) {return sml(las, sml(r...));}
void debug_out() { cout << '\n'; }
template <typename T, typename... R>
void debug_out(const T &las, const R &... r) {
    cout << las << " ";
    debug_out(r...);
}
#ifdef LH_LOCAL
#define debug(...) cout << "[" << #__VA_ARGS__ << "]: ", debug_out(__VA_ARGS__);
#else
#define debug(...) ;
#endif
/*================Header Template==============*/
const int mod = 998244353;// 998244353
int ksm(int a, int64 b, int kmod = mod) {int res = 1;for(;b > 0;b >>= 1, a = (int64)a * a % kmod) if(b &1) res = (int64)res * a % kmod;return res;}
const int INF = 0x3f3f3f3f;

---
    将上面的代码填入此处
---

int main() {
#ifdef LH_LOCAL
    freopen("D:/ACM/mtxt/in.txt", "r", stdin);
    // freopen("D:/ACM/mtxt/out.txt", "w", stdout);
#endif
    for(int cas = 1, tim = 1; cas <= tim; ++ cas) {
        work();
    }
#ifdef LH_LOCAL
    cout << "time cost:" << 1.0 * clock() / CLOCKS_PER_SEC << "s" << endl;
#endif
    return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AtCoder Beginner Contest 134 是一场 AtCoder 的入门级比赛,以下是每道题的简要题解: A - Dodecagon 题目描述:已知一个正十二边形的边长,求它的面积。 解题思路:正十二边形的内角为 $150^\circ$,因此可以将正十二边形拆分为 12 个等腰三角形,通过三角形面积公式计算面积即可。 B - Golden Apple 题目描述:有 $N$ 个苹果和 $D$ 个盘子,每个盘子最多可以装下 $2D+1$ 个苹果,求最少需要多少个盘子才能装下所有的苹果。 解题思路:每个盘子最多可以装下 $2D+1$ 个苹果,因此可以将苹果平均分配到每个盘子中,可以得到最少需要 $\lceil \frac{N}{2D+1} \rceil$ 个盘子。 C - Exception Handling 题目描述:给定一个长度为 $N$ 的整数序列 $a$,求除了第 $i$ 个数以外的最大值。 解题思路:可以使用两个变量 $m_1$ 和 $m_2$ 分别记录最大值和次大值。遍历整个序列,当当前数不是第 $i$ 个数时,更新最大值和次大值。因此,最后的结果应该是 $m_1$ 或 $m_2$ 中较小的一个。 D - Preparing Boxes 题目描述:有 $N$ 个盒子和 $M$ 个物品,第 $i$ 个盒子可以放入 $a_i$ 个物品,每个物品只能放在一个盒子中。现在需要将所有的物品放入盒子中,每次操作可以将一个盒子内的物品部取出并分配到其他盒子中,求最少需要多少次操作才能完成任务。 解题思路:首先可以计算出所有盒子中物品的总数 $S$,然后判断是否存在一个盒子的物品数量大于 $\lceil \frac{S}{2} \rceil$,如果存在,则无法完成任务。否则,可以用贪心的思想,每次从物品数量最多的盒子中取出一个物品,放入物品数量最少的盒子中。因为每次操作都会使得物品数量最多的盒子的物品数量减少,而物品数量最少的盒子的物品数量不变或增加,因此这种贪心策略可以保证最少需要的操作次数最小。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值