AtCoder Beginner Contest 362

题目链接:AtCoder Beginner Contest 362

A. Buy a Pen

tag:签到

B. Right Triangle

tag:模拟

C. Right Triangle

tag:贪心

Description:给定 n n n对整数 l i , r i l_i, r_i li,ri;求一个整数序列,满足 l i < = x i < = r i l_i <= x_i <= r_i li<=xi<=ri,且 ∑ i n x i = 0 \sum_{i}^{n}x_i = 0 inxi=0;如果没有则输出 − 1 -1 1

Solution:先判断是否有解,令 m i = ∑ i n l i , m a = ∑ i n r i mi = \sum_{i}^{n}l_i, ma = \sum_{i}^{n}r_i mi=inli,ma=inri。如果 m i < = 0 且 m a > = 0 mi <= 0 且 ma >= 0 mi<=0ma>=0有解,否则无解。

  • 先假设所有值都取最小值,则 s u m = m i sum = mi sum=mi,然后开始枚举当前位置的取值,看是否能令 s u m = 0 sum = 0 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 1 1 i i 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 a a,求不同长度的等差数列的个数( 1 < = l e n < = a . s i z e ( ) 1 <= len <= a.size() 1<=len<=a.size())。a.size() <= 80

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

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

  • 状态转移: d p [ i ] [ j ] [ k ] + = d p [ x ] [ j − 1 ] [ k ] , x < i 且 a [ k ] − a [ x ] = k dp[i][j][k] += dp[x][j - 1][k], x < i 且 a[k] - a[x] = k dp[i][j][k]+=dp[x][j1][k],x<ia[k]a[x]=k

  • 初始化:初始化长度为 2 2 2的所有答案;注意到公差的范围很大,我们使用 m a p map 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 << ' ';
    }
}
  • 18
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值