AtCoder Beginner Contest 265 A-F

AtCoder Beginner Contest 265 A-F

https://atcoder.jp/contests/abc265

A - Apple

有两种购买策略:\(x\) 元买一个苹果 or \(y\) 元买三个苹果,问买 \(n\) 个苹果最少要花多少钱

#include <bits/stdc++.h>

using namespace std;

int main () {
    int x, y, n;
    cin >> x >> y >> n;
    if (n < 3 || x * 3 <= y) {
        cout << x * n << endl;
    }
    else {
        cout << (n/3)*y + (n%3)*x;
    }
}

B - Explore

\(i-1\) 走到 \(i\) 点需要消耗 \(a_i\), 有 \(m\) 个点 \(b_i\) 存在补助,初始有 \(t\), 问能不能从 \(1\) 走到 \(n\)

注意先减再添加补助

#include <bits/stdc++.h>
#define int long long

using namespace std;
const int N = 1e5 + 5;
int n, m, t;
int a[N], b[N];

signed main () {
    cin >> n >> m >> t;
    for (int i = 2; i <= n; i++)     cin >> a[i];
    for (int i = 1; i <= m; i++) {
        int x, y;
        cin >> x >> y;
        b[x] = y;
    }

    for (int i = 2; i <= n; i++) {
        
        t -= a[i];
        if (t <= 0) {
            cout << "No\n";
            return 0;
        }
        t += b[i];
    }
    cout << "Yes\n";
}


//模拟

C - Belt Conveyor

\(n*m\) 的地图,初始在 \((1,1)\), 规则:\(U\) 向上一格,\(D\) 向下一格,\(R\) 向右一格,\(R\) 向左一格。
问走到哪里时下一步就出界,永不出界输出 \(-1\)

按题意模拟,如果走完了整个地图还不出界,则永不出界。

#include <bits/stdc++.h>

using namespace std;
const int N = 505;
int n, m;
char a[N][N];

bool check (int x, int y) {
    if (x > n || x <= 0 || y > m || y <= 0)
        return false;
    return true;
}

signed main () {
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++) {
            cin >> a[i][j];
        }

    int x = 1, y = 1, sx, sy;
    int cnt = n * m;
    while (1) {
        cnt --;
        sx = x, sy = y;
        if (a[x][y] == 'U') x --;
        else if (a[x][y] == 'D')    x ++;
        else if (a[x][y] == 'R')    y ++;
        else if (a[x][y] == 'L')    y --;
        if (!check (x, y)) {
            cout << sx << ' ' << sy;
            break;
        }
        if (cnt <= 0) {
            cout << -1;
            break;
        }
        //x = sx, y = sy;
    }
}

//一直走走到出界

D - Iroha and Haiku (New ABC Edition)

现有一数列 \(A=(A_0,...,A_{N-1})\), 问能不能找到四点 \(x,y,z,w\), 满足:

暴力 \(set\) 查找

#include <bits/stdc++.h>
#define int long long

using namespace std;
const int N = 2e5 + 5;
int n, p, q, r;
int sum[N];

signed main () {
    cin >> n >> p >> q >> r;
    set<int> s;
    s.insert (0);

    for (int i = 1; i <= n; i++) {
        int x;  cin >> x;
        sum[i] = sum[i-1] + x;
        s.insert (sum[i]);
    }

    for (int i = 1; i <= n; i++) {
        if (s.count (sum[i-1]+p) && s.count (sum[i-1]+p+q) && s.count (sum[i-1]+p+q+r)) {
            cout << "Yes\n";
            return 0;
        }
    }
    cout << "No\n";
}

//sum[y-1]-sum[x-1]=p
//sum[z-1]-sum[y-1]=q
//sum[w-1]-sum[z-1]=r

E - Warp

假设现在在 \((x,y)\), 下一步可以选择走到 \((x+A,y+B)\) or \((x+C,y+D)\) or \((x+E,y+F)\), 且有 \(m\) 个障碍, 问走 \(n\) 步能有多少种可能的路径

定义状态 \(f[i][j][k]:\) 表示 1走了 \(i\) 次,2走了 \(j\) 次,3走了 \(k\) 次。
线性 dp 路径转移即可

#include <bits/stdc++.h>
#define int long long

using namespace std;
typedef pair<int, int> pii;
const int N = 305, mod = 998244353;
int A, B, C, D, E, F, n, m;
int f[N][N][N]; //1走了i次,2走了j次,3走了k次

signed main () {
    cin >> n >> m >> A >> B >> C >> D >> E >> F;
    set<pii> s;
    for (int i = 1; i <= m; i++) {
        int x, y;
        cin >> x >> y;
        s.insert({x, y});
    }

    f[0][0][0] = 1;
    for (int i = 0; i <= n; i++)
        for (int j = 0; j <= n - i; j++)
            for (int k = 0; k <= n - i - j; k++) {
                int x = i*A + j*C + k*E, y = i*B + j*D + k*F;
                if (!i && !j && !k)     continue;
                if (s.count ({x, y}))   continue;
                if (i)  f[i][j][k] += f[i-1][j][k];
                if (j)  f[i][j][k] += f[i][j-1][k];
                if (k)  f[i][j][k] += f[i][j][k-1];
                f[i][j][k] %= mod;
            }

    int ans = 0;
    for (int i = 0; i <= n; i++)
        for (int j = 0; j <= n - i; j++) {
            ans += f[i][j][n-i-j], ans %= mod;
        }      

    cout << ans;
}

//移动n次

F - Manhattan Cafe

题意:有两点 \(p,q\), 各有 \(n\) 个维度,问有多少个点满足到 \(p\)\(q\)曼哈顿距离\(\leq d\)

分析:可以把这样的点分为两类————在 \(p,q\) 之间的,在 \(p,q\) 外的。

对于在两点之外的 \(x_i\), 每走一格,\(d_{p_i},d_{q_i}\) 都会同时 \(\pm 1\)
对于在两点之间的 \(x_i\), 则是 \(d_{p_i}+d_{q_i}=\) 定值,即 \(d_{p_i}\pm1,d_{q_i}\mp1\)

由这两种特殊性质得,可以维护矩阵的主对角线和副对角线的前缀和,即可dp 转移

#include <bits/stdc++.h>
#define int long long

using namespace std;
const int N = 1005, M = 105, mod = 998244353;
int p[M], q[M], dp[N][N], C[N][N], E[N][N];
int n, d;

signed main() {
    cin >> n >> d;
    for (int i = 0; i < n; i++)     cin >> p[i];
    for (int i = 0; i < n; i++)     cin >> q[i];
    dp[0][0] = 1;

    for (int k = 0; k < n; k++) {
        int z = abs(p[k] - q[k]);
        for (int i = 0; i <= d; i++)
            for (int j = 0; j <= d; j++) {
                C[i+1][j+1] = (C[i][j] + dp[i][j]) % mod; //主对角线
                E[i+1][j] = (E[i][j+1] + dp[i][j]) % mod; //副对角线
                dp[i][j] = (C[i][max(j-z, 0ll)] + C[max(i-z, 0ll)][j]) % mod;
                
                int m = max(z - j, 0ll);
                if (i >= m)     dp[i][j] = (dp[i][j] + E[i+1-m][j-z+m]) % mod;
                if (i >= z)     dp[i][j] = (dp[i][j] - E[i-z][j+1] + mod) % mod;
            }
    }

    int ans = 0;
    for (int i = 0; i <= d; i++)
        for (int j = 0; j <= d; j++)
            ans = (ans + dp[i][j]) % mod;
    
    cout << ans;
}
posted @ 2022-08-26 15:53  Sakana~  阅读(204)  评论(0编辑  收藏  举报