AtCoder Beginner Contest 362

题目链接:AtCoder Beginner Contest 362

A. Buy a Pen

tag:签到

B. Right Triangle

tag:模拟

C. Right Triangle

tag:贪心

Description:给定\(n\)对整数\(l_i, r_i\);求一个整数序列,满足\(l_i <= x_i <= r_i\),且\(\sum_{i}^{n}x_i = 0\);如果没有则输出\(-1\)

Solution:先判断是否有解,令\(mi = \sum_{i}^{n}l_i, ma = \sum_{i}^{n}r_i\)。如果\(mi <= 0 且 ma >= 0\)有解,否则无解。

  • 先假设所有值都取最小值,则\(sum = mi\),然后开始枚举当前位置的取值,看是否能令\(sum = 0\),否则当前值取最大值,继续向后枚举。

Competing:想到了如何判断是否有解,但是没想到贪心求解。

void solve(){
    cin >> n;
    int mi = 0, ma = 0;
    vector<pii> a(n);
    for (int i = 0; i < n; i ++){
        int l, r;
        cin >> l >> r;
        a[i] = {l, r};
        mi += l;
        ma += r;
    }
    if (mi > 0 || ma < 0){
        cout << "No\n";
    }
    else{
        cout << "Yes\n";
        for (int i = 0; i < n; i ++){  // 刚开始假设所有值都取最小值
            if (mi == 0){
                for (int j = i; j < n; j ++){
                    cout << a[j].fi << " ";
                }
                return;
            }
            mi -= a[i].fi;  // 开始选择第i个值
            if (a[i].fi <= -mi && -mi <= a[i].se){
                cout << -mi << " ";
                for (int j = i + 1; j < n; j ++){
                    cout << a[j].fi << " ";
                }
                return;
            }
            mi += a[i].se;
            cout << a[i].se << " ";      
        }
    }
}

D. Shortest Path 3

tag:Dijkstra

Description:给定一个图,每个点,边都有权值,求所有从起点\(1\)\(i\)的路径长度(边的权值 + 点的权值)。

Solution:Dijkstra板子,将权值加上点的权值即可。

void solve(){
    cin >> n >> m;
    vector g(n + 5, vector<pii>());
    vector<int> dis(n + 5, 1e15), st(n + 5);
    vector<int> a(n + 5);
    for (int i = 1; i <= n; i ++)
        cin >> a[i];

    for (int i = 0; i < m; i ++){
        int x, y, w;
        cin >> x >> y >> w;
        g[x].eb(w, y);
        g[y].eb(w, x);
    }
    auto dijkstra = [&](int u) -> void{
        dis[u] = a[u];
        priority_queue<pii, vector<pii>, greater<pii>> qu;
        qu.ep(dis[u], u);
        
        while (qu.size()){
            auto [w, y] = qu.top();
            qu.pop();
            if (st[y])
                continue;
            
            st[y] = true;
            for (auto [ww, yy] : g[y]){
                if (a[yy] + ww + w < dis[yy]){
                    dis[yy] = ww + w + a[yy];
                    qu.ep(dis[yy], yy);
                }
            }
        }
    };

    dijkstra(1);
    for (int i = 2; i <= n; i ++){
        cout << dis[i] << " ";
    } 
}

E. Count Arithmetic Subsequences

tag: dp

Description:给定一个数组\(a\),求不同长度的等差数列的个数(\(1 <= len <= a.size()\))。a.size() <= 80

Solution:因为\(a\)的长度很小,所有我们可以考虑\(dp\)

  • 状态表示:显然需要有长度和公差,然后需要一个位置。所有我们使用\(dp[i][j][k]\),表示终点为\(i\),长度为\(j\),公差为\(k\)的所有等差数列的集合。

  • 状态转移:\(dp[i][j][k] += dp[x][j - 1][k], x < i 且 a[k] - a[x] = k\)

  • 初始化:初始化长度为\(2\)的所有答案;注意到公差的范围很大,我们使用\(map\)进行离散化。

int dp[100][100][6500];
map<int, int> d;

void solve(){
    cin >> n;
    vector<int> a(n);
    int cnt = 1;
    for (int i = 0; i < n; i ++)
        cin >> a[i];
    for (int i = 0; i < n; i ++)
        for (int j = 0; j < n; j ++){
            if (!d[a[i] - a[j]])
                d[a[i] - a[j]] = cnt ++;  // 离散化
        }

    for (int i = 0; i < n; i ++){
        for (int j = 0; j < i; j ++){
            dp[i][2][d[a[i] - a[j]]] ++;  // 初始化长度为2的
        }

        for (int j = 0; j < i; j ++)
            for (int k = 3; k <= i + 1; k ++){
                dp[i][k][d[a[i] - a[j]]] += dp[j][k - 1][d[a[i] - a[j]]];
                dp[i][k][d[a[i] - a[j]]] %= mod;
            }
    }
    for (int k = 1; k <= n; k++){
        if (k == 1){
            cout << n << " ";
            continue;
        }
        int ans = 0;
        for (int i = 0; i < n; i++){
            for (int j = 1; j <= cnt; j++){
                ans += dp[i][k][j];
                ans %= mod;
            }
        }
        cout << ans << ' ';
    }
}
posted @ 2024-07-27 21:23  Sakura17  阅读(44)  评论(0)    收藏  举报