SMU Summer 2024 Contest Round 1

SMU Summer 2024 Contest Round 1

2024.7.8 9:00————11:00
过题数0/6
补题数5/6

  • AtCoder-abc126_c
  • AtCoder-abc128_d
  • AtCoder-abc134_e
  • AtCoder-abc127_e
  • AtCoder-abc131_e
  • AtCoder-abc127_d

A - Dice and Coin

读错题了以为每次都要抛掷骰子和硬币,加上不熟悉log和pow函数所以没解出来,其实应该是不难的。
题解:
有一个n面骰子,给出数字k,当结果大于等于k或等于0时游戏结束。首先抛掷骰子作为结果,然后反复抛硬币,正面结果数翻倍,反面清零。求有多大的概率赢下这场比赛,保留十二位小数。
分俩种情况考虑,抛掷数直接大于等于k,以及第一次并未大于等于k,后抛硬币的失败几率是2的n次方乘以它本身,用到log和pow函数,函数不熟悉以及注意小数单位即可。

代码:

#include<bits/stdc++.h>
using namespace std;

int main() {
    double n,k;
    cin >> n >> k;
    double ans = 0;
    for (int i = 1; i <= n; i++) {
        if (i >= k) {
            ans += (double)(n-i+1)/n;
            //注意加double
            break;
        }
        else {
            int ls = log2(k/i);
            if (i*pow(2,ls) != k) {
                ls++;
            }
            //不相等时得多抛一次
            ans += 1.0/((double)pow(2,ls))/(double)n;
        } 
    }
    printf("%0.12lf\n",ans);
    return 0;
}

B - equeue

题解:
一个双向队列,可以进行k次操作,每次操作可以在左右侧拿出或放入一个东西,必须得在拿的位置有宝石时才可进行此操作。
数据较小,可以暴力解决,遍历左右拿几个,剩余的操作次数用来放回最小的几个负数字。具体见注释。
代码:

#include<bits/stdc++.h>

using namespace std;
#define int long long
int n,k;
int v[600];

signed main() {
    cin >> n >> k;
    for (int i = 1; i <= n; i++) {
        cin >> v[i];
    }
    int ans = 0;
    for (int l = 0; l <= n; l++) {
        for (int r = 0; r <= n-l; r++) {
        //最多也就拿空了吧
            int sum = 0;
            if(l+r>k)break;
            //最多进行k次操作
            int st[600];
            memset(st,0,sizeof st);
            int tot = 0;
            for (int i = 1; i <= l; i++) {
                st[tot++] = v[i];
                sum+=v[i];
            }//本来想用优先队列的,但还是得在里面排序其实是一样的
            for (int i = n; i >= n-r+1; i--){
                st[tot++] = v[i];
                sum+=v[i];
            }
            sort(st,st+tot);
            //小的值放回去
            for (int i = 0; i < k-l-r; i++) {
                if(st[i] >= 0)break;
                //大的都得留下
                sum-=st[i];
 //               cout << sum << '.';
            }
 //           cout << l << ' ' << r << ' ' << sum << endl;
            ans = max(sum,ans);
            //寻找最大值
        }
    }
    cout << ans;
    return 0;
}

C - Sequence Decomposing

题解:
给出n个数字组成数组a,别的花里胡哨的涂颜色不管,就是求序列中最多有多少个递增子序列。

代码:

#include<bits/stdc++.h>

using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int n;
    cin >> n;
    long long a[n];
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    multiset<long long>s;
    s.insert(a[0]);
    for (int i = 1; i < n; i++) {
        auto x = s.lower_bound(a[i]);
        if (x == s.begin()){
     //       cout << i << ' ';
            s.insert(a[i]);
        }
        else {
            x--;
            s.erase(x);
            s.insert(a[i]);
        }
    }
    cout << s.size() << endl;
    return 0;
}

E - Friendships

注意一个地方,不要遇到树就走,很多是思维问题,其实可以尝试的,联通块之类的同理,也会以dfs居多。
题解:
n个节点,要求有k组i,j节点满足最小路径是2,输出一个满足条件的图。
可以想到所有节点跟1个节点相连时,可以得到最大k是(i-1)*(i-2)/2,每俩个节点之间连上一条线,就会少一种情况,就可以得出代码。
代码:

#include<bits/stdc++.h>

using namespace std;
#define int long long
int n,k;

signed main() {
    cin >> n >> k;
    if(k > (n-1)*(n-2)/2)cout << -1 << endl;
    //最多的线都不够你的要求
    else {int m = n-1+(n-1)*(n-2)/2-k;
        cout << m << endl;
    for (int i = 2; i <= n; i++) {
        cout << 1 << ' ' << i << endl;
    }
          int res = 0;
          bool st = true;
          if(k*2 == (n-1)*(n-2))return 0;
          //这里单判了一下,不然底下会先输出再停止
    for (int i = 2; i <= n; i++) {
        for (int j = i+1; j <= n; j++) {
            cout << i << ' ' << j << endl;
            res++;
            if(res == (n-1)*(n-2)/2-k){
            //这次之后就足够,其实可以直接return 0
                st = false;
                break;
            }
        }
        if(!st)break;
    }
         }
    return 0;
}

F - Integer Cards

第一道就做的这个,用了multiset,tle了,优先队列不太熟悉,加上时间不太够,没做出来。
题解:
给定n张卡片,m轮操作,每次给出b张大小为c的卡片,求替换后的最大值。
直接暴力求解会tle,必须找出有几个c,可以替换多少个,然后在相应位置替换。
代码:

#include<bits/stdc++.h>

using namespace std;

int main() {
    long long n,m;
    cin >> n >> m;
    multiset<long long>a;
    long long ln = n;
    for (int i = 0; i < n; i++) {
        long long x;
        cin >> x;
        a.insert(x);
    }
    vector<pair<int,int>>bc;
    map<int,int>mp;
    while (m--) {
        long long b,c;
        cin >> b >> c;
        mp[c]+=b;
    }
    for (auto &[c,b] : mp) {
        bc.push_back({c,b});
    }
    for (int i = bc.size(); i >= 0; i--) {
        auto [c, b] = bc[i];
        while (c > *a.begin() && b>0) {
            b--;
            a.erase(a.begin());
            a.insert(c);
        }
    }
    long long ans = 0;
    for (auto x : a) {
            ans+=x;
    }
    cout << ans << endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值