第 30 场 蓝桥·算法挑战赛 题解

1. 数学老师的第一课【算法赛】

签到题:数几个字

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

signed main()
{
    cout<<20;
	return 0;
 } 

2. 课本分配【算法赛】

思路 : 限制越大 给 越大的值 保证每个人拿到不超限制的最大

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

signed main()
{
    int n,m;
    cin>>n>>m;

    vector<int> v(n),s(m);
    for(int i=0;i<n;i++){
        cin>>v[i];
    }
    for(int j=0;j<m;j++){
        cin>>s[j];
    }

    int ans = 0;
    sort(v.rbegin(),v.rend());
    sort(s.rbegin(),s.rend());

    int idx = 0;
    for(int i=0;i<m;i++){
        for(;idx<n;idx++){
            if(v[idx] <= s[i]){
                ans += v[idx];
                idx++;
                break;
            }
        }
    }
    cout<<ans;
	return 0;
 } 

3. 开学考核【算法赛】

思路 : 最大值最小化 : 二分最大值是否可以在k次达到   ,  注意l,r取值

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

signed main(){
    int n,k,x;
    cin>>n>>k>>x;

    vector<int> a(n);
    int mx = 0; 
    for(int i=0;i<n;i++){
        cin>>a[i];
        if(a[i] > mx){
            mx = a[i]; 
        }
    }

    int l = mx - k * x;  //最差情况 : 最大值一直减
    int r = mx;         // 最好情况 : 最大值不变
    int ans = mx;       

    while(l <= r){
        int mid = (l + r) / 2;
        int num = 0; 
        for (auto i:a){
            if (i > mid){
                num += (i - mid + x - 1) / x;
                if(num > k) break; 
            }
        }
        if(num <= k){
            ans = mid;     
            r = mid - 1;   
        } else {
            l = mid + 1;  
        }
    }
    cout<<ans;
    return 0;
}

4. 新学期征程【算法赛】

思路:奇偶 分为四类, 组合数

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

const int mod = 998244353;

// 快速幂 
int p(int a,int b){
    int res=1;
    while(b){
        if(b&1) res = (res * a) % mod;
        a = (a * a) % mod;
        b >>= 1;
    }
    return res;
}

signed main(){
    int T;  
    cin>>T;
    
    while(T--){
        int n;  
        cin>>n;

        // 4种点数量 : 奇偶相同是ok
        int c0 = ((n+1)/2) * ((n+1)/2);  // 奇 奇
        int c1 = ((n+1)/2) * (n/2);  // 奇 偶
        int c2 = (n/2) * ((n+1)/2); // 偶 奇
        int c3 = (n/2) * (n/2);  // 偶 偶
        int c[4] = {c0, c1, c2, c3};

        int ans=0;
        for (int i=0;i<4;i++) {   //枚举找中点是格点的点
            if (c[i] < 2) continue; //不够两个

            int p1 = c[i] * (c[i]-1) % mod * p(2, mod-2) % mod;  // 组合数 c[i]里选2个
            
            int p2=1;
            for (int j=0;j<4;j++) {  //其他类型的不满足条件的
                if (j == i) continue;
                p2 = p2 * c[j] % mod;
            }
            
            ans = (ans + p1 * p2) % mod;
        }
        cout<<ans<<endl;
    }
    return 0;
}

5. 开学采购【算法赛】

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

signed main() {
    int n;
    cin>>n;
    
    vector<int> a(n), b(n);
    int suma=0,sumb=0; 
    for(int i=0;i<n;i++){
        cin>>a[i];
        suma+=a[i];
    }
    for(int i=0;i<n;i++){
        cin>>b[i];
        sumb+=b[i];
    }

    int m = (n + 1) / 2;

    // 桥
    vector<int> d(n);  // B  ->   A
    for (int i=0;i<n;i++) {
        d[i] = a[i]-b[i];
    }
    sort(d.begin(), d.end());
    
    //统计变便宜的
    int fu=0;
    while (fu < n && d[fu] < 0) fu++;
    
    int w1=0;
    for (int i = 0; i < fu; i++) {
        w1 += d[i];
    }
    
    // 负的不够m个
    if (fu < m) {
        for (int i = fu; i < m; i++) {
            w1 += d[i];
        }
    }

    // 蓝
    vector<int> c;   //A  -> B
    for (int i=0;i<n;i++) {
        int z = b[i] - a[i];
        if (z > 0) {  // 只要正
            c.push_back(z);
        }
    }
    sort(c.rbegin(),c.rend()); 
    
    int w2=0;
    int len=c.size(); 

    // 最多选择n-m个商品从A店改到B店
    for (int i=0;i<min(len, n - m);i++) {
        w2 += c[i];
    }

    // 小蓝的最大花费 = 全在A店购买的总价 + 从A改到B增加的花费
    // 小桥的最小花费 = 全在B店购买的总价 + 从B改到A减少的花费
    cout<<suma + w2<<" "<<sumb + w1;
    return 0;
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值